明天加入了一场电话面试,聊到了线程池,后果...

问:你先自我介绍下吧
我:
问:线程池参数
我:(这个我会)巴拉巴拉
问:提交工作的过程
我:(窃喜,还好筹备过)巴拉巴拉
问:线程池状态
我:巴拉...(卧槽,答复到线程状态下来了)
问:线程池怎么辨别外围线程和非核心线程
我:

最初一个问题,我说线程池不辨别外围和非核心,只是判断线程数量来决定是否销毁线程,后果对面讥嘲我没看过源码。是可忍孰不可忍,连忙看一波源码写文章沉着沉着。

线程池构造方法


线程池的构造方法,这些参数我想大家都会吧。外围线程数,最大线程数,存活工夫,工夫单位,阻塞队列,线程工厂,回绝策略。

线程池的ctl原子变量

ctl是什么呢?ctl创立源码如下,是原子整型。

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

下面代码外面呈现的RUNNING又是什么呢?RUNNING代码如下:

private static final int RUNNING = -1 << COUNT_BITS;

-1做位运算左移COUNT_BITS位,COUNT_BITS又是啥呢?

private static final int COUNT_BITS = Integer.SIZE - 3;@Native public static final int SIZE = 32;

COUNT_BITS为32-3=29,
-1的二进制示意为:11111111111111111111111111111111,
所以RUNNING的二进制示意为:11100000000000000000000000000000

那么ctlOf(RUNNING, 0)是什么意思呢?ctlof办法源码如下:

private static int ctlOf(int rs, int wc) { return rs | wc; }

ctl的计算是:线程运行状态和工作线程数做或运算。
所以运行状态左移29位,就是为了把低29位让给工作线程数,本人只占据高三位。为什么只须要高三位呢?因为线程的状态只有5种,三位能示意8种状态,二位能示意4种,所以选三位。

//线程池状态全副都左移COUNT_BITS 29位private static final int RUNNING = -1 << COUNT_BITS;private static final int SHUTDOWN =  0 << COUNT_BITS;private static final int STOP =  1 << COUNT_BITS;private static final int TIDYING =  2 << COUNT_BITS;private static final int TERMINATED =  3 << COUNT_BITS;

线程池还提供了ctl的拆解办法和拆解常量

//拆解办法private static int runStateOf(int c)     { return c & ~CAPACITY; }private static int workerCountOf(int c)  { return c & CAPACITY; }//拆解常量private static final int CAPACITY = (1 << COUNT_BITS) - 1;

拆解常量为什么是(1 << COUNT_BITS) - 1呢?

1的二进制是00000000000000000000000000000001COUNT_BITS上文咱们晓得29位1 << 29二进制是001000000000000000000000000000001 << 29 - 1的二进制是00011111111111111111111111111111clt & CAPACITY获取到的就是舍弃高3位之后的值clt & ~CAPACITY获取到的就是舍弃低29位之后的值

线程池的execute办法


1356行:判断线程数是否小于外围数
1357行:小于外围数则新增一个worker
1359行:1357行新增失败的状况下从新获取ctl的值
1361行:判断线程池工作状态,如果是运行态则把工作提交到workQueue阻塞队列
1363行:再次判断线程池工作状态,如果不是运行态则把工作从workQueue删除且执行回绝策略
1365行:在1363行没有执行回绝策略的根底上,如果工作线程数是零,创立一个工作线程
1368行:在1361行工作退出阻塞队列满的状况下,新增一个worker

线程池的addWorker办法


addWorker办法有点长,我收起了局部代码,否则图片太长了,不不便看。
895行:retry:地位标记,用于break,controller跳转用
596行:外层死循环,907行是内层的死循环
901行:判断线程池运行状态,如果不是运行状态,则退出办法

907行:内层for循环
909行:判断工作线程数是否大于29位或者大于外围线程数和非核心线程数
912行:cas减少工作线程数大小
913行:cas胜利退出最外层死循环
915行:从新判断线程运行状态是否扭转
916行:扭转的状况下从新执行外层循环,否则间接内层循环

925行:创立一个worker对象
929行:上锁
936行:判断线程池运行状态
938行:判断worker外面的线程是否曾经运行,曾经在运行则抛出异样
940行:把创立的worker退出队列内存
947行:开释锁
949行:如何worker创立胜利,启动worker外面的线程
956行:worker创立失败,回滚局部信息

973行:删除workers外面缓存下来的worker
974行:cas使worker计数减一
975行:尝试敞开线程池

明天先到这

我就看了下源码输入下文章,就花了几个小时,累死我了,明天先溜了