赞
踩
前言:生活是公平的,哪怕吃了很多苦,只要你坚持下去,一定会有收获,即使你失败了,你也获得了别人不具备的经历。
线程作为CPU任务调度和执行的最小单元,线程必须依赖进程而存在,在一个进程内需要并行执行多个程序,以实现不同的功能,线程的开销比进程的小(这也是引入线程的原因)。
(1)线程是Android中很重要的概念,从用途上来看,可以分为主线程和子线程,主线程也被称为UI线程,用于运行四大组件和用户的交互,处理各种和界面相关的事情。
(2)子线程用于执行耗时操作,比如IO操作、网络请求等耗时操作,(Andorid3.0以后必须要求耗时操作网络请求必须在子线程中执行)子线程不允许更新UI。否则就会造成ANR(Application Not Responding)程序无响应。
ANR:Application Not Responding,表示程序在一定时间内无法响应,造成异常。
Activity响应超过5秒;
Broadcast在处理时间超过10秒;
Service处理事件超过20秒;
上面三种情况都会导致程序出现ANR,导致这种情况的出现原因有很多,网络请求,大文件读取,耗时的计算等都会引发ANR。主线程进行了过于耗时的操作,因为Activity、Broadcast、Service都是通过主线程承载的。子线程的出现就是为了解决这个问题,Android建议耗时操作必须在子线程中运行。
在项目中大量的线程创建和销毁很容易导致GC的频繁执行,从而发生内存抖动的情况,而内存抖动对移动端最大的影响就是页面卡顿,线程的创建和销毁都是需要时间的,当有大量的线程创建和销毁时,这些时间比较明显,将导致性能上的缺失。
线程池就是用来解决这个问题,重用线程池中的线程,避免频繁的创建和销毁带来的性能消耗,能有效控制最大并发数,防止大量线程抢占资源导致系统阻塞。
(1) 重用线程池中的线程,线程执行完毕后不会立即销毁,而是等待另外的任务,这样避免了线程的频繁创建、销毁和触发GC;
(2) 有效控制线程池的最大并发数,防止大量线程抢占资源出问题;
(3) 对多线程进行统一的管理,可提供定时执行和执行间隔循环执行的功能。
Android的线程池来源于Java的Executor,Executor是一个接口,真正的线程池实现为ThreadPoolExecutor,ThreadPoolExecutor提供了一系列的参数来配置,通过不同的参数来创建不同线程池。
- public ThreadPoolExecutor(int corePoolSize,
- int maximumPoolSize,
- long keepAliveTime,
- TimeUnit unit,
- BlockingQueue<Runnable> workQueue,
- ThreadFactory threadFactory,
- RejectedExecutionHandler handler)
下面详细讲解各个参数的含义:
线程池执行流程原则:
1.如果线程池中的线程数未达到核心线程数,就会开启一个线程去执行任务;
2.如果线程池中的线程数已经达到核心线程数,而任务队列workQueue未满,则会将任务添加到workQueue任务队列中;
3.如果线程池中的线程数已经达到核心线程数但未超过最大线程数,而且任务队列workQueue已经满,则会开启非核心线程来执行任务;
4.如果线程池中的线程数已经达到最大线程数,那么拒绝该任务,执行饱和策略,抛出RejectedExecutionException异常。
ThreadPoolExecutor有两个方法供我们执行,execute()和submit()都可以执行任务。通常我们不需要返回值时使用execute()执行任务,需要返回值时使用submit(),submit()方法返回一个Future,Future可以获得结果,并且可以cancel()取消请求。
我们来验证一下上面的流程原则:
- //1.创建线程池:核心线程数为3,最大线程数为12,非核心线程保活时间为1秒,任务队列容量为4
- ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 12,
- 1, TimeUnit.SECONDS, new LinkedBlockingDeque<Runnable>(4));
- //2.创建任务:手动创建10个任务请求
- for (int i = 0; i < 10; i++) {
- final int index = i;
- Runnable runnable = new Runnable() {
- @Override
- public void run() {
- try {
- Log.e(TAG, "线程:" + Thread.currentThread().getName() + "正在执行" + index + "个任务");
- Thread.currentThread().sleep(2000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- };
- //3.线程池执行任务:将请求加入到线程池中
- executor.execute(runnable);
- }
通过new构造方法创建线程池,核心线程数为3,最大线程数为12,非核心线程保活时间为1秒,任务队列容量为4,手动创建10个任务请求,加入到线程池中;
首先打印出0,1,2说明添加了3个核心线程任务,然后3,4,5,6添加到任务队列中,任务队列只能装4个任务,这时任务队列已满,那么剩下的7,8,9任务只能放到非核心线程中执行,所以7,8,9比3,4,5,6先打印出来。任务队列的任务会等着,知道有核心线程空闲了才会执行。打印log如下:
Google官方并不推荐使用new的方法直接创建线程池,而是通过Executors方法来创建线程池,通过直接或者间接配置ThreadPoolExecutor 的参数配置构建线程池,常用的线程池有以下4中:定长线程池、定时线程池、可缓存线程池、单线程化线程池。
(1)FixedThreadPool
定长线程池:一个线程数固定的线程池,当线程空闲状态的时候,它们并不会被回收,除非线程池被关闭了,当所有线程处于活动状态的时候,新的任务会处于等待状态,直到有线程空闲才会被执行。因为只有核心线程并且线程不会被回收,核心线程没有超时机制,任务队列也没有大小限制,所以它能快速响应外界的请求。
内部实现:
- public static ExecutorService newFixedThreadPool(int nThreads) {
- return new ThreadPoolExecutor(nThreads, nThreads,
- 0L, TimeUnit.MILLISECONDS,
- new LinkedBlockingQueue<Runnable>());
- }
实例:创建核心线程数为3的定长线程池
- //1.创建定长线程池,核心线程数为3
- ExecutorService newFixedThreadPool = Executors.newFixedThreadPool(3);
- //2.创建10个任务请求
- for (int i = 0; i < 10; i++) {
- final int index = i;
- Runnable runnable = new Runnable() {
- @Override
- public void run() {
- try {
- Log.e(TAG, "线程:" + Thread.currentThread().getName() + "正在执行" + index + "个任务");
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- };
- //3.线程池执行任务
- newFixedThreadPool.execute(runnable);
- }
创建10个任务请求,线程池执行任务,执行情况应该是先执行“0,1,2”三个任务,剩下的“4,5,6,7,8,9”六个任务分别添加到任务队列中,带核心线程空闲后再执行,因为核心线程数为3,所以每次执行3个任务,直到任务执行完毕。打印log如下:
(2)ScheduledThreadPool
定时线程池:核心线程数是固定的,非核心线程数没有限制,并且非核心线程空闲的时候会立即被回收,主要用于执行定时任务和有固定周期的重复任务。
内部实现:下面中非核心线程数为Integer.MAX_VALUE,表示无穷大,没有限制。
- public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
- return new ScheduledThreadPoolExecutor(corePoolSize);
- }
-
- public ScheduledThreadPoolExecutor(int corePoolSize) {
- super(corePoolSize, Integer.MAX_VALUE,
- DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,
- new DelayedWorkQueue());
- }
实例:创建核心线程数为3个定时线程池
- //1.创建定时线程池,核心线程数为3,非核心线程数无限制
- ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
- //2.创建任务
- Runnable runnable = new Runnable() {
- @Override
- public void run() {
- Log.e(TAG, "newScheduledThreadPool线程:" + Thread.currentThread().getName() + "正在执行任务");
- }
- };
- //3.定时执行任务:延迟2秒执行,每秒执行一次任务
- scheduledExecutorService.scheduleAtFixedRate(runnable, 2, 1, TimeUnit.SECONDS);
- //scheduledExecutorService.schedule(runnable, 2, TimeUnit.SECONDS);延迟2秒执行
延迟2秒,每秒执行一次,打印log如下:
(3)CachedThreadPool
可缓存线程池:它是线程数量不定的线程池,它只有非核心线程,线程数为Integer.MAX_VALUE,表示线程数无穷大,没有限制;当线程池中的任务都处于活动状态的时候,如果有新的任务来,就创建新的线程来处理新的任务,否则就会利用空闲的线程来处理,这里的线程都有超时机制,时长为60秒,超过60秒闲置的线程就会被回收,SynchronousQueue 相当于一个空队列,导致一遇到新的任务就会立即执行。适合用于大量并且耗时较少的任务。
内部实现:
- public static ExecutorService newCachedThreadPool() {
- return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
- 60L, TimeUnit.SECONDS,
- new SynchronousQueue<Runnable>());
- }
实例:创建可缓存线程池,每秒添加一个任务
- ExecutorService newCachedThreadPool = Executors.newCachedThreadPool();
- //2.创建10个任务请求
- for (int i = 0; i < 10; i++) {
- try {
- //睡1秒,即每隔一秒执行一次
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
-
- final int index = i;
- //3.线程池执行任务
- newCachedThreadPool.execute(new Runnable() {
- @Override
- public void run() {
- try {
- Log.e(TAG, "newCachedThreadPool:" + Thread.currentThread().getName() + " 正在执行第" + index + "个任务");
- //执行任务时睡 index * 500毫秒
- Thread.sleep(index * 500);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- });
- }
上面例子中,每秒添加一个任务,每个任务执行都睡 i*500毫秒,这里演示任务执行完毕的时间,当线程不足时就开启新的线程来执行,如果有空闲的线程就会利用空闲的线程来处理任务,打印log如下:
(4)SingleThreadExecutor
单线程化线程池:它的内部有且仅有一个核心线程,他确保所有的任务都在一个线程中按照顺序执行。目的是统一外界线程到一个线程中,使得这些任务之间不需要处理线程同步的问题。不适合并发但可能引起阻塞或者影响UI线程响应的操作,比如数据库、文件操作等。
内部实现:
- public static ExecutorService newSingleThreadExecutor() {
- return new FinalizableDelegatedExecutorService
- (new ThreadPoolExecutor(1, 1,
- 0L, TimeUnit.MILLISECONDS,
- new LinkedBlockingQueue<Runnable>()));
- }
例子:创建单线程化线程池,开启10个任务请求
- //1.创建单线程化线程池
- ExecutorService newSingleThreadExecutor = Executors.newSingleThreadExecutor();
- //2.创建10个任务请求
- for (int i = 0; i < 10; i++) {
- final int index = i;
- Runnable runnable = new Runnable() {
- @Override
- public void run() {
- try {
- Log.e(TAG, "newSingleThreadExecutor线程:" + Thread.currentThread().getName() + " 正在执行" + index + "个任务");
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- };
- //3.线程池执行任务
- newSingleThreadExecutor.execute(runnable);
- }
可以看到,执行10个任务,每个任务都睡了1秒,而且每次都是唯一一个线程pool-2-thread-1 执行任务,打印log如下:
总结一下几个相关线程池的分类:
类型 | 线程类型 | 描述 | 场景 |
---|---|---|---|
FixedThreadPool: 定长线程池 | 核心线程 | 只有核心线程,线程数固定,空闲状态时,并不会被回收,除非线程池被关闭; 新任务处于等待状态,直到有线程空闲才会被执行; 没有超时机制,任务队列也没有大小限制,能快速响应外界的请求。 | 控制线程最大并发数。 |
ScheduledThreadPool : 定时线程池 | 核心+非核心线程 | 核心线程数固定,非核心线程数没有限制,非核心线程空闲即被回收。 | 执行定时任务和有固定周期的重复任务。 |
CachedThreadPool: 可缓存线程池 | 非核心线程 | 线程数量不定(没有限制)的线程池,只有非核心线程; 新任务如果有空闲线程就用空闲线程执行,否则创建新的线程执行; 有超时机制,60秒,超过60秒闲置的线程会被回收; 任务队列是空队列,遇到新的任务会立即执行。 | 适合用于大量并且耗时较少的任务。 |
SingleThreadExecutor: 单线程化线程池 | 核心线程 | 仅有一个核心线程,所有的任务都在一个线程中按照顺序执行; 不需要处理线程同步的问题。 | 单线程,不适合并发但可能引起阻塞或者影响UI线程响应的操作,比如数据库、文件操作等。 |
线程池的使用一般情况下都封装成一个管理类,方便使用:
- /**
- * 线程池管理工具类
- */
- public class ThreadPoolManager {
- private int corePoolSize;//核心线程池的数量,同时能够执行的线程数量
- private int maximumPoolSize = 100;//最大线程池数量,表示当缓冲队列满的时候能继续容纳的等待任务的数量
- private long keepAliveTime = 30 * 60;//空闲线程存活时间30分钟
- private TimeUnit unit = TimeUnit.SECONDS;//单位:秒
-
- private ThreadPoolExecutor executor;//线程池实例
- private static ThreadPoolManager mInstance;//线程池管理类
-
- public static ThreadPoolManager getInstance() {
- if (mInstance == null) {//单例
- synchronized (ThreadPoolManager.class) {//加锁
- if (mInstance == null) {
- mInstance = new ThreadPoolManager();
- }
- }
- }
- return mInstance;
- }
-
- /**
- * 私有化构造方法
- */
- private ThreadPoolManager() {
- /**
- * 给corePoolSize赋值:当前设备可用处理器核心数*2 + 1,能够让cpu的效率得到最大程度执行(有研究论证的)
- */
- corePoolSize = Runtime.getRuntime().availableProcessors() * 2 + 1;
- executor = new ThreadPoolExecutor(
- corePoolSize, //当某个核心任务执行完毕,会依次从缓冲队列中取出等待任务
- maximumPoolSize, //5,先corePoolSize,然后new LinkedBlockingQueue<Runnable>(),然后maximumPoolSize,但是它的数量是包含了corePoolSize的
- keepAliveTime, //表示的是maximumPoolSize当中等待任务的存活时间
- unit,
- new LinkedBlockingQueue<Runnable>(), //缓冲队列,用于存放等待任务,Linked的先进先出
- Executors.defaultThreadFactory(), //创建线程的工厂
- new ThreadPoolExecutor.AbortPolicy() //用来对超出maximumPoolSize的任务的处理策略
- );
- }
-
- /**
- * 执行任务
- */
- public void execute(Runnable runnable) {
- if (runnable == null) return;
- executor.execute(runnable);
- }
-
- /**
- * 从线程池中移除任务
- */
- public void remove(Runnable runnable) {
- if (runnable == null) return;
- executor.remove(runnable);
- }
- }
使用方式:
- //任务请求
- Runnable runnable = new Runnable() {
- @Override
- public void run() {
- try {
- Log.e(TAG, "线程池管理类:" + Thread.currentThread().getName() + " 正在执行任务");
- Thread.currentThread().sleep(2000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- };
- ThreadPoolManager.getInstance().execute(runnable);//执行请求
- ThreadPoolManager.getInstance().remove(runnable);//移除请求
由上面构造方法可知,可以传入自定义的拒绝策略defaultHandler,否则就是使用默认的;
- /**
- * The default rejected execution handler.
- */
- private static final RejectedExecutionHandler defaultHandler =
- new AbortPolicy();
表示无法执行任务的通知类, 当线程池无法执行任务,可能因为无法成功执行任务或者任务队列已满,这个时候就会调用ThreadPoolExecution的rejectedExecution(拒绝执行异常)方法通知调用者;
(1)AbortPolicy:默认值,拒绝任务时直接抛出异常和原因;
- /**
- *抛出一个拒绝执行任务的处理程序
- * {@code RejectedExecutionException}.
- */
- public static class AbortPolicy implements RejectedExecutionHandler {
- /**
- * Creates an {@code AbortPolicy}.
- */
- public AbortPolicy() { }
-
- /**
- * 总是抛出拒绝执行异常
- */
- public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
- throw new RejectedExecutionException("Task " + r.toString() +" rejected from " + e.toString());
- }
- }
看上面AbortPolicy源码可以知道,rejectedExecution默认会抛出一个RejectedExecutionException异常来说明当前任务为什么无法执行。RejectedExecutionHandler任务拒绝策略还提供以下几种:
(2)CallerRunsPolicy :拒绝任务时,判断线程池的状态是否为SHUTDOWN,如果为true任务则会被丢弃,如果为false任务会继续执行;
- public static class CallerRunsPolicy implements RejectedExecutionHandler {
- public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
- if (!e.isShutdown()) {
- r.run();
- }
- }
- }
(3)DiscardPolicy:拒绝任务,什么也不会发生
- public static class DiscardPolicy implements RejectedExecutionHandler {
- public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
- }
- }
(4)DiscardOldestPolicy:拒绝任务时,判断线程池的状态是否为SHUTDOWN,如果为true则任务丢弃,如果为false,将当前任务队列中等待时间最长的任务弹出,将其加入任务队列中并重试。
- public static class DiscardOldestPolicy implements RejectedExecutionHandler {
- public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
- if (!e.isShutdown()) {
- e.getQueue().poll();
- e.execute(r);
- }
- }
- }
线程池中有两个执行的方法execute()和submit(),其实两个方法的本质含义是一样的,只是有无返回值的区别。在阅读源码前我们先来看看ThreadPoolExecutor类中的几个常量的意义:
- /**
- * 获取到当前线程池的生命周期的状态
- */
- private static int runStateOf(int c) { return c & ~CAPACITY; }
- /**
- * 获取当前线程池的工作线程状态
- */
- private static int workerCountOf(int c) { return c & CAPACITY; }
- /**
- * 通过或运算拼接线程的生命周期状态和工作线程的个数
- */
- private static int ctlOf(int rs, int wc) { return rs | wc; }
(1)execute():我们来看看execute()的源码:
- public void execute(Runnable command) {
- if (command == null)
- throw new NullPointerException();
- //获取当前线程的生命周期对应的二进制状态码
- int c = ctl.get();
- //当前线程数量是否少于核心线程数量,如果小于就直接创建核心线程执行任务,成功则跳出方法,失败则继续往下走
- if (workerCountOf(c) < corePoolSize) {
- if (addWorker(command, true))
- return;
- c = ctl.get();
- }
- //判断线程池是否为Running状态,并且将任务添加到队列中
- if (isRunning(c) && workQueue.offer(command)) {
- int recheck = ctl.get();
- //审核下的线程状态如果不是Running状态则直接移除队列中
- if (! isRunning(recheck) && remove(command))
- reject(command);
- //如果当前线程数为0,则单独创建线程而不是指定任务
- else if (workerCountOf(recheck) == 0)
- addWorker(null, false);
- }
- //如果不满足上述条件,尝试创建一个非核心线程来执行任务,如果创建失败则会reject()
- else if (!addWorker(command, false))
- reject(command);
- }
execute()的流程图:
那么我们可以看出addWorker()才是创建线程(核心、非核心)的主要方法,而reject()则是一个创建线程失败的回调,看一下源码:
- final void reject(Runnable command) {
- handler.rejectedExecution(command, this);
- }
通过handler将通知发出去,然后针对不同类型的RejectedExecutionHandler,进行不同的处理。
(2)addWorker():我们来看看addWorker()的源码:
- //firstTask:需要执行的任务,也可以为null(单纯的创建线程执行任务)
- //core:创建的线程是否需要核心线程
- private boolean addWorker(Runnable firstTask, boolean core) {
- retry://java标识符,防止在多线程的情况下,compareAndIncrementWorkerCount()计算线程池状态出现问题
- for (;;) {
- int c = ctl.get();
- int rs = runStateOf(c);
-
- // Check if queue empty only if necessary.
- //1.线程处于stop或者即将处于stop状态
- //2.线程处于SHUTDOWN状态,并且传递的任务为null,队列不为空,需要增加线程,其他不需要
- if (rs >= SHUTDOWN &&
- ! (rs == SHUTDOWN &&
- firstTask == null &&
- ! workQueue.isEmpty()))
- return false;
-
- for (;;) {
- int wc = workerCountOf(c);
- //当前工作的线程数量是否超过最大值,或者超过核心线程数(core:表示是否需要核心线程)和最大线程数
- if (wc >= CAPACITY ||
- wc >= (core ? corePoolSize : maximumPoolSize))
- return false;
- //线程池统计是否更新成功,成功则跳出循环,继续执行,不成功则跳出外循环继续执行
- if (compareAndIncrementWorkerCount(c))
- break retry;
- c = ctl.get(); // Re-read ctl
- if (runStateOf(c) != rs)
- continue retry;
- // else CAS failed due to workerCount change; retry inner loop
- }
- }
-
- //线程创建过程,Worker是包装类,分别对创建成功和失败做了处理
- boolean workerStarted = false;
- boolean workerAdded = false;
- Worker w = null;
- try {
- //创建线程
- w = new Worker(firstTask);
- final Thread t = w.thread;
- if (t != null) {
- //线程加锁
- final ReentrantLock mainLock = this.mainLock;
- mainLock.lock();
- try {
- // Recheck while holding lock.
- // Back out on ThreadFactory failure or if
- // shut down before lock acquired.
- int rs = runStateOf(ctl.get());
-
- //线程处于Running状态或者处于SHUTDOWN状态并且任务不为空
- if (rs < SHUTDOWN ||
- (rs == SHUTDOWN && firstTask == null)) {
- if (t.isAlive()) // precheck that t is startable
- throw new IllegalThreadStateException();
- workers.add(w);
- int s = workers.size();
- //容量的判断
- if (s > largestPoolSize)
- largestPoolSize = s;
- workerAdded = true;
- }
- } finally {
- mainLock.unlock();
- }
- //线程增加成功,设置成功标记
- if (workerAdded) {
- t.start();
- workerStarted = true;
- }
- }
- } finally {
- //如果线程未启动则分发到添加线程失败
- if (! workerStarted)
- addWorkerFailed(w);
- }
- //如果添加成功返回true,添加失败返回false
- return workerStarted;
- }
我们来看看addWorkerFailed()方法:回滚线程的创建操作,如果线程的包装类Worker存在就移除掉,刷新工作线程数量,尝试终止线程操作;
- private void addWorkerFailed(Worker w) {
- final ReentrantLock mainLock = this.mainLock;
- mainLock.lock();
- try {
- if (w != null)
- //移除worker
- workers.remove(w);
- //刷新线程数量
- decrementWorkerCount();
- //尝试停止操作
- tryTerminate();
- } finally {
- mainLock.unlock();
- }
- }
tryTerminate():尝试停止线程池操作,1.如果在SHUTDOWN状态并且队列为空时;2.stop状态,两种情况会将线程池进行停止操作,
- final void tryTerminate() {
- for (;;) {
- int c = ctl.get();
- //Running状态或者已停止状态TERMINATED或者SHUTDOWN状态并且任务队列不为空
- if (isRunning(c) ||
- runStateAtLeast(c, TIDYING) ||
- (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
- return;
- //如果线程数量不为空,终止一个线程
- if (workerCountOf(c) != 0) { // Eligible to terminate
- interruptIdleWorkers(ONLY_ONE);
- return;
- }
-
- final ReentrantLock mainLock = this.mainLock;
- mainLock.lock();
- try {
- //设置当前线程状态为TIDYING,如果不成功则继续循设置
- if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
- try {
- terminated();
- } finally {
- //最终线程池状态为停止状态
- ctl.set(ctlOf(TERMINATED, 0));
- //设置可重新入锁的标志,将被锁隔离的在外面等待的线程唤醒
- termination.signalAll();
- }
- return;
- }
- } finally {
- mainLock.unlock();
- }
- // else retry on failed CAS
- }
- }
interruptIdleWorkers():设置线程中断的操作,onlyOne如果为true:只中断工作线程中的其中一个线程;如果为false:中断所有的工作线程。t.interrupt():表示中断线程。
- private void interruptIdleWorkers(boolean onlyOne) {
- final ReentrantLock mainLock = this.mainLock;
- mainLock.lock();
- try {
- for (Worker w : workers) {
- Thread t = w.thread;
- //检查线程的状态,如果未拦截并且有锁就拦截
- if (!t.isInterrupted() && w.tryLock()) {
- try {
- //中断线程
- t.interrupt();
- } catch (SecurityException ignore) {
- } finally {
- w.unlock();
- }
- }
- //如果onlyOne = true则只执行一次就跳出
- if (onlyOne)
- break;
- }
- } finally {
- mainLock.unlock();
- }
- }
addWorker()方法流程图:
(3)shutdown():中断所有空闲线程的方法,它的核心方法还是调用了上面的interruptIdleWorkers()方法。
- public void shutdown() {
- final ReentrantLock mainLock = this.mainLock;
- mainLock.lock();
- try {
- //校验线程的状态
- checkShutdownAccess();
- //设置线程池的状态为SHUTDOWN
- advanceRunState(SHUTDOWN);
- //中断所有空闲进程,内部调用interruptIdleWorkers(false)
- interruptIdleWorkers();
- //中断所有线程可指定的操作,需要自己实现
- onShutdown(); // hook for ScheduledThreadPoolExecutor
- } finally {
- mainLock.unlock();
- }
- tryTerminate();
- }
-
- private void interruptIdleWorkers() {
- interruptIdleWorkers(false);
- }
注意:1.在shutdown()被执行时,可以让现有的任务被执行关闭,但是新的任务不会再被处理;
2.如果任务线程时SHUTDOWN状态,继续调用shutdown()不会产生任何效果。
submit()其实还需要调用execute()去执行任务,而execute()和submit()本质不同的是submit()将包装好的任务进行返回。
- public Future<?> submit(Runnable task) {
- if (task == null) throw new NullPointerException();
- RunnableFuture<Void> ftask = newTaskFor(task, null);
- //最终还是调用execute(ftask)
- execute(ftask);
- return ftask;
- }
-
- //创建RunnableFuture
- protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
- return new FutureTask<T>(runnable, value);
- }
-
- //FutureTask其实就是包装了callable 和其他一些信息的类
- public FutureTask(Runnable runnable, V result) {
- this.callable = Executors.callable(runnable, result);
- this.state = NEW; // ensure visibility of callable
- }
Future<?>则是返回的结果,里面封装了请求等信息,我们可以通过cancel(boolean),true表示中断退出正在执行的任务,false则是任务可以被完成。
至此,本文结束!
源码地址:https://github.com/FollowExcellence/AndroidOptimizeDemo
请尊重原创者版权,转载请标明出处:https://blog.csdn.net/m0_37796683/article/details/103054999 谢谢!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。