很多时候,我们为了保证项目中线程数量不会乱飙升,不好管理,我们会使用线程池,保证线程在我们的管理之下。
我们也经常说:使用线程池复用线程。
那么问题是:
- 线程池中的线程是如何复用的?是执行完成后销毁,再新建几个放那;还是始终是那几个线程(针对 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
方法会一直阻塞,直到拿到元素为止。吃饭去。
小缘,厉害!
我留下了不学无术的泪水
点赞,学习了