@@ -74,7 +74,7 @@ CAPACITY: 00011111 11111111 11111111 11111111
7474总结:掩码就是“过滤器”,CAPACITY 这个掩码专门用来从 ctl 里取出 workerCount。
7575
7676## 线程池相关状态
77- 线程池完整生命周期图:
77+ 线程池完整生命周期图(图1)
7878
7979<!-- 这是一张图片,ocr 内容为: -->
8080![ ] ( https://cdn.nlark.com/yuque/0/2026/png/12890164/1780810463940-3a2fb7db-c019-4d2a-88ed-b395d768d830.png )
@@ -182,6 +182,8 @@ private static final int TERMINATED = 3 << COUNT_BITS;
182182```
183183
184184## 二进制图总结
185+ 图2
186+
185187<!-- 这是一张图片,ocr 内容为: -->
186188![ ] ( https://cdn.nlark.com/yuque/0/2026/png/12890164/1780810735409-8b698335-3b31-4cc0-a3cf-d4f57367ac50.png )
187189
@@ -551,8 +553,6 @@ wt.interrupt() 不是杀线程,而是给工作线程设置**<font style="color
551553
552554
553555
554-
555-
556556> ** 第二层:为什么要调用 Thread.interrupted()之后,还要再次判断runStateAtLeast(ctl.get(), STOP)**
557557>
558558
@@ -569,9 +569,11 @@ wt.interrupt() 不是杀线程,而是给工作线程设置**<font style="color
569569
570570
571571
572- 三层判断总体意思就是:只要线程池已经进入 STOP 状态,就要求 worker 必须是中断状态。如果 worker 还不是中断状态,就补一次 interrupt。
572+ 三层判断总体意思就是:只要线程池已经进入 STOP 状态,就要求 worker 必须是中断状态。如果 worker 还不是中断状态,就补一次 interrupt。只要线程池已经进入 STOP,就确保当前 worker 线程带着中断标记执行任务。
573+
573574
574575
576+ 这一段复杂的判断主要是应对shutdownNow()触发的线程池状态=STOP的场景,而shutdown()是会tryLock()竞争锁,拿不到锁则不会对worker发起中断。
575577
576578## getTask()
577579getTask()的作用:是 ThreadPoolExecutor 里 Worker 从阻塞队列获取任务的核心方法。
@@ -780,6 +782,29 @@ public List<Runnable> shutdownNow() {
780782
781783
782784
785+ shutdownNow()会立马让线程池状态推进到STOP,然后调用interruptWorkers()中断所有worker,因此worker在runWorker()中拿到锁准备执行用户任务task.run()之前,也要先进行判断:
786+
787+ ``` java
788+ if ((runStateAtLeast(ctl. get(), STOP ) ||
789+ (Thread . interrupted() &&
790+ runStateAtLeast(ctl. get(), STOP ))) &&
791+ ! wt. isInterrupted())
792+ // 只要线程池已经进入 STOP,就确保当前 worker 线程带着中断标记执行任务。
793+ wt. interrupt();
794+ ```
795+
796+ wt.interrupt()最后还是会给执行用户任务的线程标记“中断”,最后中断是否会导致worker线程“结束”任务,具体看用户线程是否调用了能响应中断的逻辑,比如:
797+
798+ ``` java
799+ Thread . sleep()
800+ BlockingQueue . take()
801+ Condition . await()
802+ ```
803+
804+ 这类方法会抛出InterruptedException提前结束。
805+
806+ 或者任务代码自己判断 Thread.currentThread().isInterrupted(),然后主动退出。如果用户任务完全不理中断,比如死循环不检查中断,那么 shutdownNow()也不能强制让它停下来。
807+
783808### shutdown和shutdownNow的区别
784809> ** <font style =" color :#DF2A3F ;" >shutdown</font >**
785810>
@@ -832,3 +857,74 @@ try {
832857
833858
834859
860+
861+
862+
863+
864+ ## 线程池任务调用流程图
865+ 图3
866+
867+ <!-- 这是一张图片,ocr 内容为: -->
868+ ![ ] ( https://cdn.nlark.com/yuque/0/2026/png/12890164/1780886199772-60d2b78f-8991-4c11-afe9-8211912af596.png )
869+
870+ # 其他细节
871+ ## execute()入队之后的二次检查
872+ execute() 入队后的二次检查,不只是防止任务丢失
873+
874+ ``` java
875+ if (isRunning(c) && workQueue. offer(command)) {
876+ int recheck = ctl. get();
877+ if (! isRunning(recheck) && remove(command))
878+ reject(command);
879+ else if (workerCountOf(recheck) == 0 )
880+ addWorker(null , false );
881+ }
882+ ```
883+
884+ 二次检查作用:防止线程池关闭后任务被错误保留,以及队列有任务但没有 worker 执行。
885+
886+
887+
888+ ## Worker本身就是一个锁(AQS)
889+ 源码中可以看到,Worker继承了AbstractQueuedSynchronizer
890+
891+ ``` java
892+ Worker extends AbstractQueuedSynchronizer
893+ ```
894+
895+ 因此在调用runWorker()时会先加锁,然后执行用户任务,等结束了再释放锁:
896+
897+ ``` java
898+ ...
899+ w. lock();
900+ ...
901+ task. run();
902+ ...
903+ w. unlock();
904+ ```
905+
906+ 这段代码核心作用:标记当前 worker 正在执行任务,防止 shutdown() 中断它。但是没法防止shutdownNow()进行中断,中断与否则是要看用户任务,在上文shutdownNow()有详细分析。
907+
908+ ## 核心线程和非核心线程没有身份标记
909+ 线程池里没有字段标记:
910+
911+ ``` plain
912+ 这个 worker 是核心线程
913+ 那个 worker 是非核心线程
914+ ```
915+
916+ 而是动态判断:
917+
918+ ``` plain
919+ workerCount > corePoolSize
920+ ```
921+
922+ 超过 ` corePoolSize ` 的线程,空闲时就可能被回收。
923+
924+ ## 拒绝策略不只在队列满时触发
925+ 常见理解是:队列满 + 线程数满 -> reject
926+
927+ 但其实还有:线程池不是 RUNNING 状态,也会 reject。
928+
929+ 例如已经shutdown()后再提交任务,则会被reject。
930+
0 commit comments