不知道大家学习线程池时有没有这个疑问,创建线程池时如果用的无界队列(或者比较大的队列),核心线程数设置为 0,按照网上说的线程池的任务执行流程,队列不满不会创建非核心线程,那不炸了吗?任务永远执行不了?
网上普遍的线程池工作流程图:
先说结论
即使核心线程数设置为 0,提交一个任务后线程池也会创建一个线程去执行。
代码验证
- 核心线程数为 0,线程池中会创建一个线程,任务会由这个线程顺序执行
public static void main(String[] args) throws InterruptedException {
// 配置:核心 0,最大 5,存活 60 秒
ThreadPoolExecutor executor = new ThreadPoolExecutor(
0, 5, 60, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100)
);
// 提交 10 个任务
for (int i = 0; i < 10; i++) {
int cur = i;
executor.execute(() -> {
System.out.println(cur +"执行,线程:" + Thread.currentThread().getName());
});
}
}
- 为了更加清楚执行过程中线程池的情况:
public static void main(String[] args) throws InterruptedException {
// 配置:核心 0,最大 5,存活 60 秒
ThreadPoolExecutor executor = new ThreadPoolExecutor(
0, 5, 60, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100)
);
// 提交 3 个任务
for (int i = 0; i < 3; i++) {
int cur = i;
executor.execute(() -> {
System.out.println(cur + "执行,线程:" + Thread.currentThread().getName());
try {
Thread.sleep(500); // 模拟任务执行时间
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
// 打印当前线程池状态
System.out.println("=== 提交任务 " + i + " 后 ===");
System.out.println("核心线程数:" + executor.getCorePoolSize());
System.out.println("最大线程数:" + executor.getMaximumPoolSize());
System.out.println("当前线程数:" + executor.getPoolSize());
System.out.println("活跃线程数:" + executor.getActiveCount());
System.out.println("队列大小:" + executor.getQueue().size());
System.out.println("完成任务数:" + executor.getCompletedTaskCount());
System.out.println("========================\n");
Thread.sleep(1000);
}
// 等待所有任务完成
Thread.sleep(3000);
System.out.println("\n=== 最终状态 ===");
System.out.println("当前线程数:" + executor.getPoolSize());
System.out.println("活跃线程数:" + executor.getActiveCount());
System.out.println("队列大小:" + executor.getQueue().size());
System.out.println("完成任务数:" + executor.getCompletedTaskCount());
}
可以看出线程池中始终只有一个线程在处理任务
- 再看一下正常情况下,比如设置核心线程数为 2,会有两个线程会并发执行。
public static void main(String[] args) throws InterruptedException {
// 配置:核心 2,最大 5,存活 60 秒
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, 5, 60, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100)
);
// 提交 10 个任务
for (int i = 0; i < 10; i++) {
int cur = i;
executor.execute(() -> {
System.out.println(cur +"执行,线程:" + Thread.currentThread().getName());
});
}
}
源码分析(debug)
一层层扒开源码看一下整个流程。
- 任务提交时,可以看到线程池无线程
- 走到 execute 方法里面,这时可以队列中加入一个任务,接着会走进
workerCountOf(recheck) == 0这个判断里(即线程数为 0),这是个兜底策略,针对核心线程数为 0 的特殊情况
execute完整源码:
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
- 接着进入addWorker 方法,就可以看到这里会创建一个线程去执行任务,可以看到线程数为 1
addWorker 完整源码:
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (int c = ctl.get();;) {
// Check if queue empty only if necessary.
if (runStateAtLeast(c, SHUTDOWN)
&& (runStateAtLeast(c, STOP)
|| firstTask != null
|| workQueue.isEmpty()))
return false;
for (;;) {
if (workerCountOf(c)
>= ((core ? corePoolSize : maximumPoolSize) & COUNT_MASK))
return false;
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
if (runStateAtLeast(c, SHUTDOWN))
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
int c = ctl.get();
if (isRunning(c) ||
(runStateLessThan(c, STOP) && firstTask == null)) {
if (t.getState() != Thread.State.NEW)
throw new IllegalThreadStateException();
workers.add(w);
workerAdded = true;
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
最后
你以为是 bug? 设计线程池的大佬早就预料到了!