动态线程池中修改核心线程数比当前线程数要少,会不会影响正在执行的线程任务
目录
一、源码
二、interruptIdleWorkers() 源码
三、结论一句话
四、附:验证代码
不会。
在 ThreadPoolExecutor
里调 setCorePoolSize()
把核心线程数设得比当前活动线程数小时,不会中断或回收任何正在执行的任务。JDK 的实现逻辑是:
- 只会把“下一次”创建 Worker 时的核心阈值降低;
- 线程池会等到工作线程自然空闲(
getTask()
返回null
)后,再根据 当前工作线程数 > 新核心线程数 的条件回收多余的 Worker; - 正在
run()
的任务继续跑完,不会被强停。
因此,正在执行的任务不会受影响,只是当这批任务完成后,线程池会逐步把总线程数收缩到新的核心线程数。
一、源码
public void setCorePoolSize(int corePoolSize) {if (corePoolSize < 0 || maximumPoolSize < corePoolSize)throw new IllegalArgumentException();int delta = corePoolSize - this.corePoolSize;this.corePoolSize = corePoolSize; // ① 先修改阈值// ② 当前工作线程数 > 新阈值 → 只中断“空闲”线程if (workerCountOf(ctl.get()) > corePoolSize)interruptIdleWorkers(); // 见下方源码// ③ 新阈值变大 → 按需补充线程else if (delta > 0) {int k = Math.min(delta, workQueue.size());while (k-- > 0 && addWorker(null, true)) {if (workQueue.isEmpty())break;}}
}
二、interruptIdleWorkers()
源码
private void interruptIdleWorkers() {interruptIdleWorkers(false); // onlyOne=false
}private void interruptIdleWorkers(boolean onlyOne) {final ReentrantLock mainLock = this.mainLock;mainLock.lock();try {for (Worker w : workers) {Thread t = w.thread;// 关键:线程必须“未持有任务”才会被打断if (!t.isInterrupted() && w.tryLock()) {try {t.interrupt();} finally {w.unlock();}}if (onlyOne)break;}} finally {mainLock.unlock();}
}
w.tryLock()
只有在 Worker 处于getTask()
等待 时才会成功;- 正在
runTask()
的 Worker 已经拿到了锁,因此 不会 被打断。
三、结论一句话
降低核心线程数时,只会在任务执行结束后、线程空闲时再回收;正在跑的任务不会被中断或强制停止。
四、附:验证代码
ThreadPoolExecutor pool = new ThreadPoolExecutor(5, 10, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>());// 先提交 5 个耗时任务
for (int i = 0; i < 5; i++) {pool.execute(() -> {System.out.println(Thread.currentThread().getName() + " start");try { Thread.sleep(3000); } catch (InterruptedException ignored) {}System.out.println(Thread.currentThread().getName() + " end");});
}Thread.sleep(1000); // 确保线程已启动
pool.setCorePoolSize(2); // 把核心数降到 2
System.out.println("核心线程数已设为 2,但正在运行的任务继续执行...");
输出示例:
pool-1-thread-1 start
pool-1-thread-2 start
...
核心线程数已设为 2,但正在运行的任务继续执行...
pool-1-thread-1 end
pool-1-thread-2 end
...
所有任务都完整跑完后,多余的线程才被回收,与源码逻辑完全吻合。