很多时候,我们为了保证项目中线程数量不会乱飙升,不好管理,我们会使用线程池,保证线程在我们的管理之下。
我们也经常说:使用线程池复用线程。
那么问题是:
- 线程池中的线程是如何复用的?是执行完成后销毁,再新建几个放那;还是始终是那几个线程(针对 coreSize 线程)。
- 问题 1 的结论具体实现细节(说清楚流程即可)?
更多问答 >>
-
2019-12-20 00:08
-
每日一问 Activity 都重建了,你 Fragment凭什么活着?
2019-12-23 23:19 -
每日一问 ViewPager 嵌套,“老子”怎么就没拦住你?
2019-12-29 23:52 -
每日一问 很多书籍上写:“事件分发只有一次 ACTION_DOWN,一次 ACTION_UP”严谨吗?
2020-01-07 00:08 -
每日一问 为什么 Dialog 默认弹出后 Activity 就无法响应用户事件了?
2020-01-15 19:24 -
每日一问 Android 签名机制 v1 v2 v3 , 卧槽都 v3 了?
2019-12-09 23:52 -
2019-12-04 00:18
-
每日一问 | Activity启动流程中,大部分都是用Binder通讯,为啥跟Zygote通信的时候要用socket呢?
2019-11-30 20:49 -
2019-11-26 00:12
-
2019-11-22 00:10

线程池中的线程是如何复用的?
其实我们调用线程池的execute方法(ExecutorService的submit方法最终也是调用execute)传进去的Runnable,并不会直接以new Thread(runnable).start()的方式来执行,而是通过一个正在运行的线程来调用我们传进去的Runnable的run方法的。那么,这个正在运行的线程,在执行完传进去的Runnable的run方法后会销毁吗?看情况。大部分场景下,我们都是通过Executors的newXXX方法来创建线程池的,就拿newCachedThreadPool来说:看第三个参数(
keepAliveTime):60L,后面的单位是秒,也就是说,newCachedThreadPool方法返回的线程池,它的工作线程(也就是用来调用Runnable的run方法的线程)的空闲等待时长为60秒,如果超过了60秒没有获取到新的任务,那么这个工作线程就会结束。如果在60秒内接到了新的任务,那么它会在新任务结束后重新等待。还有另一种常用的线程池,通过
newFixedThreadPool方法创建的:它跟上面的
可以看到第三个参数设置成了0,这就说明,newCachedThreadPool方法一样,创建的都是ThreadPoolExecutor的对象,只是参数不同而已。如果当前工作线程数>corePoolSize时,并且有工作线程在执行完上一个任务后没拿到新的任务,那么这个工作线程就会立即结束。再看第二个参数(maximumPoolSize),它设置成了跟corePoolSize一样大,也就是说当前工作线程数 永远不会大于corePoolSize了,这样的话,即使有工作线程是空闲的,也不会主动结束,会一直等待下一个任务的到来。源码分析:
我们来探究一下ThreadPoolExecutor是如何管理线程的。先来看精简后的execute方法:逻辑很清晰:当
execute方法被调用时,如果当前工作线程 < corePoolSize(上面ThreadPoolExecutor构造方法的第一个参数)的话,就会创建新的线程,否则加入队列。加入队列后如果没有工作线程在运行,也会创建一个。好,接着看它是怎么创建新线程的:
主要是创建Worker对象并启动它里面的线程,来看看Worker里面是怎么样的:
可以看到,这个Worker也是一个Runnable。构造方法里面还创建了一个Thread,这个
再看Thread对象,对应了上面addWorker方法启动的那个thread。run方法,它调用了runWorker,并把自己传了进去:Worker里面的
执行完成之后,接着就会通过firstTask,就是我们通过execute方法传进去的Runnable,可以看到它会在这个方法里面被执行。getTask方法尝试从等待队列中(上面的workQueue)获取下一个任务,如果getTask方法返回null的话,那么这个工作线程就会结束。最后来看看getTask方法:emmm,就像刚刚说的那样,如果是
newCachedThreadPool的话:那么当执行到
getTask方法时,里面的timed肯定每次都是true的,也就是每次获取任务的时候,最多只能等60秒,如果60秒内没有获取到新的任务,那么getTask就会返回null(工作线程会结束)。像
newFixedThreadPool,如果我们传的是5:那么,它的参数是:
在判断当前工作线程数是否大于核心线程数的时候,肯定就是
false了,因为在前面提交任务的时候,就已经有判断:小于核心线程数才创建新的工作线程。timed是false的话,从workQueue中取任务的时候,调用的就不是poll方法,而是take方法,这个take方法会一直阻塞,直到拿到元素为止。吃饭去。
小缘,厉害!
我留下了不学无术的泪水
点赞,学习了