线程池核心线程数设为 0 会怎样?(附源码解析)
不知道大家学习线程池时有没有这个疑问,创建线程池时如果用的无界队列(或者比较大的队列),核心线程数设置为 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? 设计线程池的大佬早就预料到了!
