2021年第一篇文章~~
线程池策略
当一个任务通过execute(Runnable)方法添加到线程池时:
- 线程数量小于corePoolSize,新建线程数来处理被添加的任务。
- 线程数量大于等于corePoolSize,存在空闲线程,使用空闲线程执行新任务。
- 线程数量大于等于corePoolSize,不存在空闲线程,新任务被添加到等待队列,添加成功则等待空闲线程;
- 添加失败:线程数量小于最大线程数,新建线程执行新任务;线程数量等于最大线程数,则拒绝此任务。
Okhttp线程池配置
1 | public synchronized ExecutorService executorService() { |
可以看出,创建的线程池核心线程数为0,最大线程数MAX_VALUE,闲置时间60s,队列SynchronousQueue。这样的参数配置出来的线程池高并发,最大吞吐量。
那么为什么Okhttp的线程池队列用的SynchronousQueue而不是其他的?我们先看个栗子:
1 | public void testQueue(){ |
这里用的ArrayBlockingQueue,传的capacity为1。如果任务1是个耗时的操作,那么任务2得不到执行。我们可以看一下ThreadPoolExecutor的源码:
1 | public void execute(Runnable command) { |
那么我再加一个任务3呢?
1 | public void testQueue(){ |
这次可以执行了,不过得到的执行顺序为:任务1、任务3、任务2。为什么呢?因为当任务3进来了后添加不到队列了,而此时线程数量小于最大线程数,所以新建线程执行了任务3,当任务3执行完后会从队列里取任务2执行。
所以用ArrayBlockingQueue存在问题,哪怕把capacity改为别的数(除了0),也存在这样的问题。
那么LinkedBlockingDeque呢?LinkedBlockingDeque内部用的是链表结构,ArrayBlockingQueue用的是数组。LinkedBlockingDeque可以传capacity,也可以不传,不传的话有默认的为Integer.MAX_VALUE。它的效果其实是跟ArrayBlockingQueue一样的,也是有上述的问题。
而SynchronousQueue是一个没有容量的队列,往里面添加永远失败,会开一个线程去执行。(当然了是在线程数量小于最大线程数的情况下,不过这个应该可以保证啦)不会因为谁把谁堵住而得不到执行。