今天参加了一场电话面试,聊到了线程池,结果...
问:你先自我介绍下吧
我:
问:线程池参数
我:(这个我会)巴拉巴拉
问:提交任务的过程
我:(窃喜,还好准备过)巴拉巴拉
问:线程池状态
我:巴拉...(卧槽,回答到线程状态上去了)
问:线程池怎么区分核心线程和非核心线程
我:
最后一个问题,我说线程池不区分核心和非核心,只是判断线程数量来决定是否销毁线程,结果对面嘲讽我没看过源码。是可忍孰不可忍,赶紧看一波源码写文章冷静冷静。
线程池构造方法
线程池的构造方法,这些参数我想大家都会吧。核心线程数,最大线程数,存活时间,时间单位,阻塞队列,线程工厂,拒绝策略。
线程池的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的二进制是00000000000000000000000000000001
COUNT_BITS上文我们知道29位
1 << 29二进制是00100000000000000000000000000000
1 << 29 - 1的二进制是00011111111111111111111111111111
clt & 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行:尝试关闭线程池
今天先到这
我就看了下源码输出下文章,就花了几个小时,累死我了,今天先溜了