一道简单的面试题,看出候选人是否看过线程池的源码。实践出真知,一直停留在看的层面上是很难进步的。一起看一下吧
ExecutorService threadPool = Executors.newFixedThreadPool(2);
for (int i = 0; i < 4; i++) {
threadPool.execute(() -> sleep(1000));
}
threadPool.shutdown();
分析
看网上有些人说,比如如下言论:
shutdown只是将线程池的状态设置为SHUTWDOWN状态,正在执行的任务会继续执行下去,没有被执行的则中断。
而shutdownNow则是将线程池的状态设置为STOP,正在执行的任务则被停止,没被执行任务的则返回。
怎么得出来的呢?
进行对比一下就明显看的出来:
- 在源码层面上,shutdown调用的是advanceRunState(SHUTDOWN),而shutdownNow调用的是(STOP)
- shutdown调用的事中断空闲的Workers,而shutdownNow调用的是中断所有的Workers
- shutdownNow会把所有任务队列中的任务取出来,返回一个任务列表

advanceRunState区别
比较不容易理解的advanceRunState到底做了什么事情。
- targetState参数的使用值只有两个:SHUTDOWN与STOP
- SHUTDOWN值为0
- STOP值为1<<29 = 2^29。 二进制表示的话1后面29个0
假设传的参数是SHUTDOWN:
- ctlOf(targetState, workerCountOf(c)) = workerCountOf(c) > 0,一般就是线程池的个数
假设传的参数是STOP: 2^29
- ctlOf(targetState, workerCountOf(c)) = 2^29 + 2 , 为STOP状态
/**
* 从运行的状态过渡到targetState
* 如果当前已经大于了targetState,就什么都不做。
*/
private void advanceRunState(int targetState) {
for (;;) {
int c = ctl.get();
if (runStateAtLeast(c, targetState) ||
ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
break;
}
}
如图:
targetState为STOP时

targetState为SHUTDOWN时

最后
把上面的结论再拿出来,shutdown与shutdownNow有什么区别呢?
- shutdown调用的是advanceRunState(SHUTDOWN),而shutdownNow调用的是(STOP),即调用后设置的线程池状态不同
- shutdown调用的是中断空闲的Workers,而shutdownNow调用的是中断所有的Workers
- shutdownNow会把所有任务队列中的任务取出来,返回一个任务列表。而shutdown什么都不返回。
关键点:线程池状态,中断的线程数量,返回结果
网友评论