参考地址:http://blog.csdn.net/qq_30379689/article/details/72550701#面向对象和面向过程的区别
http://blog.csdn.net/csdn_aiyang/article/details/65442540
http://blog.csdn.net/lmj623565791/article/details/47079737/

一、多线程的三种实现方式

  1. 继承Thread类,重写run函数方法
  2. 实现Runnable接口,重写run函数方法
  3. 实现Callable接口,重写call函数方法,ExecutorService、Callable、Future实现有返回结果的多线程
  4. Callable和Runnable的不同之处:

        ①Callable规定的方法是call(),而Runnable规定的方法是run().②Callable的任务执行后可返回值,而Runnable的任务是不能返回值的③call()方法可抛出异常,而run()方法是不能抛出异常的。④运行Callable任务可拿到一个Future对象,Future表示异步计算的结果。通过Future对象可了解任务执行情况,可取消任务的执行。
    

二、如何停止一个线程

  1. 创建一个标识(flag),当线程完成你所需要的工作后,可以将标识设置为退出标识
  2. 使用Thread的interrupt()方法和nterrupted()方法,两者配合break退出循环,或者return来停止线程,有点类似标识(flag)
  3. 可以使用try-catch语句,在try-catch语句中抛出异常,强行停止线程进入catch语句,这种方法可以将错误向上抛,使线程停止事件得以传播

三、Thread 线程状态和相关方法


此图来自http://blog.csdn.net/qq_30379689/article/details/72550701#面向对象和面向过程的区别,如果不能用请告知,我这里主要以做笔记为主,此图直观的反映线程的变化状态

  1. 可运行(runnable):线程对象创建后,线程调用start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu的使用权
  2. 运行(running):可运行状态(runnable)的线程获得了cpu使用权,执行程序代码
  3. 阻塞(block):线程因为某种原因放弃了cpu使用权,即让出了cpu使用权,暂时停止运行,直到线程进入可运行(runnable)状态,才有机会再次获得cpu使用权转到运行(running)状态。阻塞的情况分三种:

    • 等待阻塞:运行(running)的线程执行o.wait()方法,JVM会把该线程放入等待队列(waitting queue)中
    • 同步阻塞:运行(running)的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则JVM会把该线程放入锁池(lock pool)中
    • 其他阻塞:运行(running)的线程执行Thread.sleep(long ms)或t.join()方法,或者发出了I/O请求时,JVM会把该线程置为阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入可运行(runnable)状态
  4. 死亡(dead):线程run()、main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期,且死亡的线程不可再次复生

sleep和wait的区别

  • sleep()是Thread类的方法,wait()是Object类中的方法;
  • 调用sleep(),在指定的时间里,暂停程序的执行,让出CPU给其他线程,当超过时间的限制后,又重新恢复到运行状态,在这个过程中,线程不会释放对象锁;调用wait()时,线程会释放对象锁,进入此对象的等待锁池中,只有此对象调用notify()时,线程进入运行状态

什么叫守护线程,用什么方法实现守护线程

守护线程:指为其他线程的运行提供服务的线程,可通过setDaemon(boolean on)方法设置线程的Daemon模式,true为守护模式,false为用户模式

方法介绍

  1. wait() :使一个线程处于等待状态,并且释放所有持有对象的lock锁,直到notify()/notifyAll()被唤醒后放到锁定池(lock blocked pool ),释放同步锁使线 程回到可运行状态(Runnable)。
  2. sleep():使一个线程处于睡眠状态,是一个静态方法,调用此方法要捕捉Interrupted异常,醒来后进入runnable状态,等待JVM调度。
  3. notify():使一个等待状态的线程唤醒,注意并不能确切唤醒等待状态线程,是由JVM决定且不按优先级。
  4. notifyAll():使所有等待状态的线程唤醒,注意并不是给所有线程上锁,而是让它们竞争。
  5. join():使一个线程中断,IO完成会回到Runnable状态,等待JVM的调度。
  6. Synchronized():使Running状态的线程加同步锁使其进入(lock blocked pool ),同步锁被释放进入可运行状态(Runnable)。

五、如何实现线程的同步

1. Synchronized方法

当用此关键字修饰方法时, 内置锁会保护整个方法。在调用该方法前,需要获得内置锁,否则就处于阻塞状态。注: synchronized关键字也可以修饰静态方法,此时如果调用该静态方法,将会锁住整个类。

  • 同步方法:给一个方法增加synchronized修饰符之后就可以使它成为同步方法,这个方法可以是静态方法和非静态方法,但是不能是抽象类的抽象方法,也不能是接口中的接口方法。当任意一个线程进入到一个对象的任意一个同步方法时,这个对象的所有同步方法都被锁定了,在此期间,其他任何线程都不能访问这个对象的任意一个同步方法,直到这个线程执行完它所调用的同步方法并从中退出,从而导致它释放了该对象的同步锁之后。在一个对象被某个线程锁定之后,其他线程是可以访问这个对象的所有非同步方法的。
  • 同步块:同步块是通过锁定一个指定的对象,来对同步块中包含的代码进行同步;而同步方法是对这个方法块里的代码进行同步,而这种情况下锁定的对象就是同步方法所属的主体对象自身。如果这个方法是静态同步方法呢?那么线程锁定的就不是这个类的对象了,也不是这个类自身,而是这个类对应的java.lang.Class类型的对象。同步方法和同步块之间的相互制约只限于同一个对象之间,所以静态同步方法只受它所属类的其它静态同步方法的制约,而跟这个类的实例(对象)没有关系。
    如果一个对象既有同步方法,又有同步块,那么当其中任意一个同步方法或者同步块被某个线程执行时,这个对象就被锁定了,其他线程无法在此时访问这个对象的同步方法,也不能执行同步块。synchronized 关键字用于保护共享数据。

2. 使用特殊域变量(volatile)实现线程同步

volatile关键字为域变量的访问提供了一种免锁机制,相当于告诉虚拟机该域可能会被其他线程更新,因此每次使用该域就要重新计算,而不是使用寄存器中的值,不能用来修饰final类型的变量

3. 使用重入锁ReentrantLock类实现线程同步

ReentrantLock类是可重入、互斥、实现了Lock接口的锁,方法:
ReentrantLock() : 创建一个ReentrantLock实例
lock() : 获得锁
unlock() : 释放锁,通常在finally代码释放锁

private Lock lock = new ReentrantLock();
public void save(int money) {lock.lock();try{account += money;}finally{lock.unlock();}}

4. 使用ThreadLocal局部变量实现线程同步

如果使用ThreadLocal管理变量,则每一个使用该变量的线程都获得该变量的副本,副本之间相互独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。

 private static ThreadLocal<Integer> account = new ThreadLocal<Integer>(){@Overrideprotected Integer initialValue(){return 100;}};

ThreadLocal与同步机制都是为了解决多线程中相同变量的访问冲突问题,前者采用以”空间换时间”的方法,后者采用以”时间换空间”的方式

5. 使用阻塞队列LinkedBlockingQueue实现线程同步

LinkedBlockingQueue是一个基于已连接节点的,范围任意的blocking queue。 队列是先进先出的顺序(FIFO
LinkedBlockingQueue 类常用方法:
LinkedBlockingQueue() : 创建一个容量为Integer.MAX_VALUE 的 LinkedBlockingQueue
put(E e) : 在队尾添加一个元素,如果队列满则阻塞
size() : 返回队列中的元素个数
take() : 移除并返回队头元素,如果队列空则阻塞
代码实例: 实现商家生产商品和买卖商品的同步
当队列满时:
  add()方法会抛出异常
  offer()方法返回false
  put()方法会阻塞

6. 使用原子变量AtomicXxx实现线程同步

Xxx 可以是 String ,Integer等
原子操作就是指将读取变量值、修改变量值、保存变量值看成一个整体来操作即-这几种行为要么同时完成,要么都不完成。
AtomicInteger类常用方法:
AtomicInteger(int initialValue) : 创建具有给定初始值的新的AtomicInteger
addAddGet(int dalta) : 以原子方式将给定值与当前值相加
get() : 获取当前值
原子操作主要有:
对于引用变量和大多数原始变量(long和double除外)的读写操作;  
对于所有使用volatile修饰的变量(包括long和double)的读写操作。

7. 使用线程池进行管理及优化

1. Android HandlerThread

public class HandlerThreadActivity extends AppCompatActivity{private HandlerThread mCheckMsgThread;private Handler mCheckMsgHandler;//与UI线程管理的handlerprivate Handler mHandler = new Handler();@Overrideprotected void onCreate(Bundle savedInstanceState){super.onCreate(savedInstanceState);setContentView(R.layout.activity_thread_handler);//创建后台线程initBackThread();}private void initBackThread(){mCheckMsgThread = new HandlerThread("check-message-coming");mCheckMsgThread.start();mCheckMsgHandler = new Handler(mCheckMsgThread.getLooper()){@Overridepublic void handleMessage(Message msg){checkForUpdate();if (isUpdateInfo){mCheckMsgHandler.sendEmptyMessageDelayed(MSG_UPDATE_INFO, 1000);}}};}/*** 模拟从服务器解析数据*/private void checkForUpdate(){try{//模拟耗时Thread.sleep(1000);mHandler.post(new Runnable(){@Overridepublic void run(){String result = "实时更新中,当前大盘指数:<font color='red'>%d</font>";result = String.format(result, (int) (Math.random() * 3000 + 1000));mTvServiceInfo.setText(Html.fromHtml(result));}});} catch (InterruptedException e){e.printStackTrace();}}@Overrideprotected void onDestroy(){super.onDestroy();//释放资源mCheckMsgThread.quit();}
}

HandlerThread 的源码

public class HandlerThread extends Thread {int mPriority;int mTid = -1;Looper mLooper;public HandlerThread(String name) {super(name);mPriority = Process.THREAD_PRIORITY_DEFAULT;}protected void onLooperPrepared() {}@Overridepublic void run() {mTid = Process.myTid();Looper.prepare();synchronized (this) {mLooper = Looper.myLooper();notifyAll();}Process.setThreadPriority(mPriority);onLooperPrepared();Looper.loop();mTid = -1;}

Looper.loop()的核心代码:

while (true) {  Message msg = queue.next(); // might block  if (msg != null) {  if (msg.target == null) {  // No target is a magic identifier for the quit message.  return;  }  long wallStart = 0;  long threadStart = 0;  // This must be in a local variable, in case a UI event sets the logger  Printer logging = me.mLogging;  if (logging != null) {  logging.println(">>>>> Dispatching to " + msg.target + " " +  msg.callback + ": " + msg.what);  wallStart = SystemClock.currentTimeMicro();  threadStart = SystemClock.currentThreadTimeMicro();  }  msg.target.dispatchMessage(msg); public void quit() {  Message msg = Message.obtain();  // NOTE: By enqueueing directly into the message queue, the  // message is left with a null target.  This is how we know it is  // a quit message.  mQueue.enqueueMessage(msg, 0);
}  

是一个无限循环,退出循环的条件是:msg.target == null;
也就是说,如果我们向此looper的MessageQueue发送一个target为null的message,就可以停止这个线程的远行。

停止HandlerThread的方法就是使用quit方法,具体调用形式如下:
mHandlerThread.getLooper().quit();

2. 线程池管理

new Thread(new Runnable() {

@Override
public void run() {// TODO Auto-generated method stub
}

}).start();

这样new出来的匿名对象会存在一些问题

  • 由于是匿名的,无法对它进行管理
  • 如果需要多次执行这个操作就new多次,可能创建多个,占用系统资源
  • 无法执行更多的操作

使用线程池的好处:
可以重复利用存在的线程,减少系统的开销;利用线程池可以执行定时、并发数的控制

线程池的作用:
线程池作用就是限制系统中执行线程的数量。

原理:根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果;少了浪费了系统资源,多了造成系统拥挤效率不高。用线程池控制线程数量,其他线程排队等候。一个任务执行完毕,再从队列的中取最前面的任务开始执行。若队列中没有等待进程,线程池的这一资源处于等待。当一个新任务需要运行时,如果线程池中有等待的工作线程,就可以开始运行了;否则进入等待队列。

为什么要用线程池:

1.减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
2.可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器瘫痪(每个线程需要大约
1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。

Java通过Executors提供四种线程池

newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。

newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

android 多线程实现方式、并发与同步学习总结相关推荐

  1. Android 多线程实现方式

    该原创文章首发于微信公众号"字节流动" Android 多线程实现方式 通常来说,一个应用至少有一个进程,而一个进程至少有一个线程. 线程是 CPU 调度的基本单位,进程是系统资源 ...

  2. Android多线程实现方式及并发与同步,架构师必备技能

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8rwcQW4s-1620361703648)(//upload-images.jianshu.io/upload_ima ...

  3. Android多线程实现方式及并发与同步,技术详细介绍

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fdcyorlw-1617703305737)(//upload-images.jianshu.io/upload_ima ...

  4. Linux、Windows、Android跨平台可视化方式进行文件同步——syncthing使用教程

    1.在国产Linux发行版deepin/UOS之间进行文件同步 1.1.通过深度应用商店一键安装syncthing 国产Linux发行版deepin或UOS一直致力于将Linux更加易用,使得没有Li ...

  5. java同步锁售票_Java基础学习笔记: 多线程,线程池,同步锁(Lock,synchronized )(Thread类,ExecutorService ,Future类)(卖火车票案例)...

    学习多线程之前,我们先要了解几个关于多线程有关的概念. 进程:进程指正在运行的程序.确切的来说,当一个程序进入内存运行,即变成一个进程,进程是处于运行过程中的程序,并且具有一定独立功能. 线程:线程是 ...

  6. Android多线程源码学习笔记一:handler、looper、message、messageQueue

    最近在学习Android多线程相关知识的源码,现在把自己的笔记整理一下,写出来加深印象. Android多线程通讯的核心是handler.looper.message.messageQueue,这篇文 ...

  7. 多线程&高并发(全网最新:面试题 + 导图 + 核心学习笔记)面试手稳心不慌,轻松拿下 offer,秋招跳槽必不可少的底层能力

    前言 当你开始开始去跳槽面试的时候,明明只是一份 15K 的工作,却问你会不会多线程,懂不懂高并发,火箭造得让你猝及不防,结果就是凉凉:现如今市场,多线程.高并发编程.分布式.负载均衡.集群等可以说是 ...

  8. android java 多线程,Android多线程的四种方式

    当我们启动一个App的时候,Android系统会启动一个Linux Process,该Process包含一个Thread,称为UI Thread或Main Thread.通常一个应用的所有组件都运行在 ...

  9. Android多线程之同步锁的使用

    本文主要介绍了Android多线程之同步锁的使用,分享给大家,具体如下: 一.同步机制关键字synchronized 对于Java来说,最常用的同步机制就是synchronized关键字,他是一种基于 ...

最新文章

  1. 天际汽车牛胜福:受感知系统等影响 点对点L3将于五年后实现...
  2. 论文笔记之:Action-Decision Networks for Visual Tracking with Deep Reinforcement Learning
  3. eq,neq,gt,lt等表达式缩写
  4. rust布料怎么弄_布料“难弄”,你需要从这六方面解决!
  5. 数据预处理(part1)--单个预测变量数据变换R语言
  6. Linux环境安装zookeeper3.5.5后,总是启动不了
  7. mysql注入技巧原理_MySQL注入技巧总结
  8. 证券期货行业监管大数据治理方案研究
  9. Android 图片缩略图显示
  10. linux 命令行删除分区,如何在 Linux 中删除分区
  11. Ubuntu学习日记--Lesson2:创建、重命名、删除文件及文件夹,强制清空回收站方法
  12. 嵌入式系统——系统可靠度计算
  13. 用ultraiso安装linux系统教程,使用UltraISO制作ubuntu安装u盘启动盘图文教程
  14. sql(mysql快捷键)
  15. java 金额千位用逗号隔开_金额格式化 处理千分位 金额逗号,隔开
  16. uniGui删除服务器文件,彻底取消unigui /server页面
  17. 数值策划的自我修养(一):任务流程的修改
  18. OKHttp3的使用和详解
  19. 递推 SDUT 王小二切饼
  20. 快速查询QQ多少人对你设置了特别关心源码

热门文章

  1. 小巧精致的真无线耳机,音质很不错,瓷音未来Mars体验
  2. 450家!智能工厂、智慧交通、智慧警务、智慧社区等细分领域龙头全名单!
  3. 《我的青春谁做主》经典台词一网打尽 搞笑并霹雳
  4. java排序算法对比_java项目 实现排序算法对比,步骤,改进
  5. 如何将pyecharts交互性图表在PPT中显示
  6. python期末考试及答案a卷_Python数据分析与数据可视化知到APP期末考试完整答案...
  7. Mac OS X查看ip地址
  8. Leetcode Solutions - Part 1
  9. 抖音 Android 性能优化系列:Java 内存优化篇
  10. ida 调试android之路