线程池 execute() 的工作逻辑
原文地址:https://www.xilidou.com/2018/02/09/thread-corepoolsize/
最近在看《Java并发编程的艺术》回顾线程池的原理和参数的时候发现一个问题,如果 corePoolSize = 0 且 阻塞队列是无界的。线程池将如何工作?
我们先回顾一下书里面描述线程池execute()工作的逻辑:
- 如果当前运行的线程,少于corePoolSize,则创建一个新的线程来执行任务。
- 如果运行的线程等于或多于 corePoolSize,将任务加入 BlockingQueue。
- 如果 BlockingQueue 内的任务超过上限,则创建新的线程来处理任务。
- 如果创建的线程数是单钱运行的线程超出 maximumPoolSize,任务将被拒绝策略拒绝。
看了这四个步骤,其实描述上是有一个漏洞的。如果核心线程数是0,阻塞队列也是无界的,会怎样?如果按照上文的逻辑,应该没有线程会被运行,然后线程无限的增加到队列里面。然后呢?
于是我做了一下试验看看到底会怎样?
1 | public class threadTest { |
结果里面的System.out.println(atomicInteger.getAndAdd(1));语句执行了,与上面的描述矛盾了。到底发生了什么?线程池创建线程的逻辑是什么?我们还是从源码来看看到底线程池的逻辑是什么?
ctl
要了解线程池,我们首先要了解的线程池里面的状态控制的参数 ctl。
- 线程池的ctl是一个原子的 AtomicInteger。
- 这个ctl包含两个参数 :
- workerCount 激活的线程数
- runState 当前线程池的状态
- 它的低29位用于存放当前的线程数, 因此一个线程池在理论上最大的线程数是 536870911; 高 3 位是用于表示当前线程池的状态, 其中高三位的值和状态对应如下:
- 111: RUNNING
- 000: SHUTDOWN
- 001: STOP
- 010: TIDYING
- 110: TERMINATED
为了能够使用 ctl 线程池提供了三个方法:
1 | // Packing and unpacking ctl |
execute
外界通过 execute 这个方法来向线程池提交任务。
先看代码:
1 |