线程的生命周期状态你烂熟于心,那线程池呢?Running/ShutDown/Stop/Tidying/Terminated

在 Java 中,线程池(ThreadPoolExecutor)的生命周期状态是由其内部状态机管理的,主要通过 ctl(control)变量来跟踪线程池的运行状态和线程数量。线程池的生命周期状态有以下几种,分别对应不同的运行阶段:

线程池的生命周期状态

  1. RUNNING(运行状态)

    • 描述: 这是线程池的初始状态,表示线程池可以接受新任务,并且会处理队列中的现有任务。
    • 条件 :
      • 新提交的任务会被分配给线程执行。
      • 如果核心线程数未达到上限,会创建新线程。
      • 如果核心线程数已满,且任务队列未满,任务会被加入队列。
    • 状态值 : RUNNING 的状态值在 ctl 中是负数(最高位为 0)。
  2. SHUTDOWN(关闭状态)

    • 描述: 线程池不再接受新的任务,但会继续执行队列中已有的任务以及正在运行的任务。
    • 触发方式 : 调用 shutdown() 方法。
    • 条件 :
      • 新提交的任务会被拒绝(抛出 RejectedExecutionException)。
      • 线程池会等待所有任务执行完毕后进入终止状态。
    • 状态值 : SHUTDOWN 的状态值为 0。
  3. STOP(停止状态)

    • 描述: 线程池不再接受新任务,也不会继续处理队列中的任务,并且会尝试中断正在执行的任务。
    • 触发方式 : 调用 shutdownNow() 方法。
    • 条件 :
      • 返回队列中未执行的任务列表。
      • 正在运行的线程会被中断(通过 interrupt())。
    • 状态值 : STOP 的状态值为 1。
  4. TIDYING(整理状态)

    • 描述: 这是线程池的一个过渡状态,表示所有任务都已经完成(或被中断),线程池正在准备进入终止状态。
    • 条件 :
      • SHUTDOWN 状态下,任务队列为空且活动线程数为 0。
      • STOP 状态下,活动线程数为 0。
    • 状态值 : TIDYING 的状态值为 2。
    • 行为 : 线程池会调用 terminated() 方法(可由开发者重写)来执行清理工作。
  5. TERMINATED(终止状态)

    • 描述: 线程池完全终止,不再有任何活动。
    • 条件 : 从 TIDYING 状态转换而来,terminated() 方法执行完毕后进入此状态。
    • 状态值 : TERMINATED 的状态值为 3。
    • 行为: 线程池资源被释放,无法再恢复使用。

状态转换流程

以下是线程池状态的典型转换路径:

  • RUNNINGSHUTDOWN : 调用 shutdown() 方法。
  • RUNNINGSTOP : 调用 shutdownNow() 方法。
  • SHUTDOWNTIDYING: 任务队列为空且所有线程完成任务。
  • STOPTIDYING: 所有线程被中断或完成。
  • TIDYINGTERMINATED : terminated() 方法执行完毕。

代码中的体现

ThreadPoolExecutor 的源码中,状态是通过 ctl 的高 3 位来表示的(基于位运算)。例如:

java 复制代码
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3; // 29位用于线程计数
private static final int RUNNING    = -1 << COUNT_BITS;
private static final int SHUTDOWN   =  0 << COUNT_BITS;
private static final int STOP       =  1 << COUNT_BITS;
private static final int TIDYING    =  2 << COUNT_BITS;
private static final int TERMINATED =  3 << COUNT_BITS;

示例代码

以下是一个简单的线程池生命周期演示:

java 复制代码
import java.util.concurrent.*;

public class ThreadPoolDemo {
    public static void main(String[] args) {
        ThreadPoolExecutor executor = new ThreadPoolExecutor(2, 4, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(2));

        // 提交任务
        for (int i = 0; i < 5; i++) {
            executor.execute(() -> {
                try {
                    Thread.sleep(1000);
                    System.out.println(Thread.currentThread().getName() + " 执行任务");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }

        // 关闭线程池
        executor.shutdown(); // 进入 SHUTDOWN 状态
        // executor.shutdownNow(); // 进入 STOP 状态

        try {
            executor.awaitTermination(5, TimeUnit.SECONDS); // 等待终止
            System.out.println("线程池已终止: " + executor.isTerminated());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
相关推荐
码事漫谈20 分钟前
勿删
后端
IT_陈寒4 小时前
用了Proxy才发现以前的JavaScript白写了
前端·人工智能·后端
唐青枫5 小时前
别把 ArrayList 当成会自动管理内存的 List:Zig 动态数组从入门到实战
后端
鸿蒙开发5 小时前
我为 HarmonyOS 做了一个统一大模型 SDK:@hmkit/ai 正式开源
后端
猪是念来过倒5 小时前
Semaphore 与 RateLimiter:并发控制双雄详解
后端
掘金者阿豪5 小时前
异构数据同步最怕什么?不是同步慢,而是数据对不上
后端
程序员cxuan6 小时前
Claude 官方的学习教程,太强了。
人工智能·后端·程序员
老孙讲技术6 小时前
把工地遮挡和掉线接进项目部:setMessageCallback 订 alarm 与 deviceStatus
后端·物联网·音视频开发
老孙讲技术6 小时前
关店后有人进门,监控值班群却没响:用 setMessageCallback 订 human,再用 aiHuman 打开人形
后端·物联网·音视频开发
LEE6 小时前
原来 Claude Code 最厉害的工具,一行代码都不写
前端·后端