Skip to content

线程池创建线程的状态

概述

  • 定义
  • 线程池(ThreadPoolExecutor)是 Java 并发框架中用于管理线程的工具,通过复用线程执行任务,避免频繁创建/销毁线程的开销。
  • 线程池中的线程在生命周期中会经历不同的状态,这些状态由 线程本身的状态Thread.State)和 线程池的内部管理机制 共同决定。
  • 核心点
  • Java 线程有 6 种状态(NEW, RUNNABLE, BLOCKED, WAITING, TIMED_WAITING, TERMINATED)。
  • 线程池创建和管理线程时,线程的状态主要涉及 NEW, RUNNABLE, WAITING, TIMED_WAITING, 和 TERMINATED,具体取决于线程池的工作流程(如任务分配、空闲等待、终止)。

1. Java 线程状态

根据 java.lang.Thread.State,线程的 6 种状态如下: - NEW:线程创建但尚未启动(new Thread() 后,调用 start() 前)。 - RUNNABLE:线程正在运行或准备运行(包括 CPU 执行或等待 CPU 调度)。 - BLOCKED:线程等待锁(例如等待 synchronized 块/方法的监视器锁)。 - WAITING:线程无限期等待另一线程的动作(如 Object.wait()Thread.join())。 - TIMED_WAITING:线程有限期等待(如 Thread.sleep()Object.wait(timeout))。 - TERMINATED:线程执行完成或异常退出。

在线程池中,BLOCKED 状态较少见(因线程池任务通常避免锁竞争),以下重点分析线程池创建线程时的状态。


2. 线程池创建线程时的状态

线程池(ThreadPoolExecutor)创建线程的流程涉及线程的初始化、任务执行、空闲等待和终止等阶段,各阶段对应的线程状态如下:

(1) 线程创建(NEW)

  • 场景
  • 线程池初始化或任务量增加时,创建新线程以处理任务。
  • 线程池通过 ThreadFactory 创建线程(如 Executors.defaultThreadFactory())。
  • 状态
  • NEW:线程对象创建但未调用 start()
  • 线程池调用 new Thread() 创建线程,处于 NEW 状态。
  • 流程
  • 线程池检查当前线程数是否低于 corePoolSize 或任务队列满时是否允许扩展至 maximumPoolSize
  • 调用 ThreadFactory.newThread(Runnable) 创建线程。
  • 示例java ThreadFactory factory = Executors.defaultThreadFactory(); Thread thread = factory.newThread(() -> System.out.println("Task")); // thread.getState() == Thread.State.NEW

(2) 线程启动(RUNNABLE)

  • 场景
  • 线程池调用 Thread.start() 启动线程,线程进入执行状态。
  • 线程开始运行 ThreadPoolExecutor.Worker.run(),从任务队列获取任务。
  • 状态
  • RUNNABLE
    • 线程正在执行任务(CPU 运行)。
    • 线程等待 CPU 调度(就绪状态)。
    • 线程在 run() 中调用 BlockingQueue.take()poll() 获取任务。
  • 流程
  • 线程池通过 addWorker() 添加 Worker(封装线程和任务)。
  • 调用 worker.thread.start(),线程进入 Worker.run()
  • 线程循环执行 runWorker(),从队列获取任务并运行。
  • 示例java ExecutorService pool = Executors.newFixedThreadPool(1); pool.submit(() -> System.out.println("Task")); // 线程启动后,状态为 RUNNABLE

(3) 空闲等待任务(WAITING 或 TIMED_WAITING)

  • 场景
  • 线程执行完任务后,任务队列为空,线程等待新任务。
  • 线程池中的核心线程(corePoolSize)或非核心线程等待任务。
  • 状态
  • WAITING
    • 线程调用 BlockingQueue.take(),无限期等待任务(核心线程默认)。
    • 内部实现:LinkedBlockingQueue.take() 阻塞。
  • TIMED_WAITING
    • 线程调用 BlockingQueue.poll(timeout),有限期等待任务(非核心线程或配置了 keepAliveTime)。
    • 若超时无任务,线程可能被销毁。
  • 流程
  • 线程执行完任务后,调用 getTask() 获取新任务。
  • 若队列为空:
    • 核心线程:queue.take()WAITING)。
    • 非核心线程:queue.poll(keepAliveTime)TIMED_WAITING)。
  • 示例java ThreadPoolExecutor pool = new ThreadPoolExecutor( 1, 2, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>()); // 核心线程空闲 -> WAITING // 非核心线程空闲 -> TIMED_WAITING (最多等待 60 秒)

(4) 任务执行(RUNNABLE)

  • 场景
  • 线程从队列获取任务并执行。
  • 状态
  • RUNNABLE
    • 线程执行任务的 run() 方法。
    • 若任务涉及 I/O 或计算,线程仍为 RUNNABLE(包括等待 CPU)。
  • BLOCKED(少见):
    • 若任务中使用 synchronized 并等待锁,线程可能短暂进入 BLOCKED
    • 线程池设计通常避免锁竞争,BLOCKED 不常见。
  • 流程
  • Worker.runWorker() 调用任务的 Runnable.run()Callable.call()
  • 执行期间,线程保持 RUNNABLE
  • 示例java pool.submit(() -> { System.out.println("Running task"); Thread.sleep(1000); // 仍为 RUNNABLE });

(5) 线程终止(TERMINATED)

  • 场景
  • 线程完成任务且无需继续运行(非核心线程超时或线程池关闭)。
  • 线程池调用 Thread.interrupt() 或任务抛出异常导致线程退出。
  • 状态
  • TERMINATED
    • 线程执行完 run() 方法或被中断,生命周期结束。
    • 线程对象不可重用,需重新创建。
  • 流程
  • 非核心线程空闲超时(keepAliveTime),getTask() 返回 null,退出循环。
  • 线程池关闭(shutdown()shutdownNow()),中断所有线程。
  • 线程执行完 runWorker(),进入 TERMINATED
  • 示例java pool.shutdown(); // 线程执行完任务后 -> TERMINATED

(6) 特殊情况:BLOCKED(不常见)

  • 场景
  • 任务逻辑中使用了 synchronized 或其他锁,导致线程等待。
  • 状态
  • BLOCKED:线程等待监视器锁(Monitor)。
  • 原因
  • 线程池任务通常设计为无锁或低竞争,BLOCKED 状态罕见。
  • 若发生,可能是任务实现不当(如同步访问共享资源)。
  • 示例java pool.submit(() -> { synchronized (lock) { // 若 lock 被其他线程持有,线程进入 BLOCKED } });

3. 线程池线程状态变迁

以下是线程池中线程的典型状态变迁:

NEW -> RUNNABLE -> WAITING/TIMED_WAITING -> RUNNABLE -> TERMINATED
  |        |            |                      |            |
创建    启动并执行   空闲等待任务           再次执行任务     终止
  • 创建NEWRUNNABLE(调用 start())。
  • 执行任务RUNNABLE
  • 空闲等待
  • 核心线程:WAITINGqueue.take())。
  • 非核心线程:TIMED_WAITINGqueue.poll(timeout))。
  • 再次执行WAITING/TIMED_WAITINGRUNNABLE(获取任务)。
  • 终止RUNNABLETERMINATED(任务完成或池关闭)。
  • 特殊RUNNABLEBLOCKED(任务中等待锁,少见)。

状态图

       +---------+
       |   NEW   |
       +---------+
            |
            v
       +---------+       Task Done/Queue Empty
       | RUNNABLE|<------------------------+
       +---------+                         |
            |                              |
            v                              |
       +---------+       Get Task          |
       | WAITING |------------------------>|
       +---------+                         |
            |                              |
            v                              |
       +---------------+                   |
       | TIMED_WAITING |------------------>|
       +---------------+   Timeout/Shutdown
            |
            v
       +------------+
       | TERMINATED |
       +------------+

4. 线程池状态管理的关键点

  • Worker 封装
  • ThreadPoolExecutor.Worker 封装线程和任务,线程的 run() 调用 runWorker(),管理任务执行和状态切换。
  • 任务队列
  • 线程通过 BlockingQueue(如 LinkedBlockingQueue)获取任务,阻塞等待导致 WAITING/TIMED_WAITING
  • 核心与非核心线程
  • 核心线程(corePoolSize)长期存活,空闲时 WAITING
  • 非核心线程(maximumPoolSize)空闲超时后终止,涉及 TIMED_WAITING
  • 中断处理
  • 线程池关闭或任务取消时,调用 Thread.interrupt(),线程从 WAITING/TIMED_WAITING 退出,进入 TERMINATED
  • 线程复用
  • 线程池通过复用线程(保持 RUNNABLEWAITING)减少 NEWTERMINATED 的开销。

5. 代码示例

import java.util.concurrent.*;

public class ThreadPoolStateExample {
    public static void main(String[] args) throws InterruptedException {
        ThreadPoolExecutor pool = new ThreadPoolExecutor(
            1, 2, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<>(),
            r -> {
                Thread t = new Thread(r, "Pool-Thread");
                System.out.println("Created thread: " + t.getName() + ", State: " + t.getState());
                return t;
            });

        // 提交任务
        pool.submit(() -> {
            System.out.println("Task running in: " + Thread.currentThread().getName() +
                              ", State: " + Thread.currentThread().getState());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        // 等待空闲
        Thread.sleep(2000);
        System.out.println("Thread state after task: " + pool.getActiveCount() + " active threads");

        // 关闭线程池
        pool.shutdown();
        pool.awaitTermination(5, TimeUnit.SECONDS);
        System.out.println("Pool terminated");
    }
}

输出示例

Created thread: Pool-Thread, State: NEW
Task running in: Pool-Thread, State: RUNNABLE
Thread state after task: 0 active threads
Pool terminated
  • NEW:线程创建时。
  • RUNNABLE:任务执行时。
  • WAITING:任务完成后线程空闲。
  • TERMINATED:线程池关闭后。

6. 注意事项

  • 状态监控
  • 使用 Thread.getState() 或 JMX 监控线程状态。
  • 示例:ThreadMXBean 查看线程池状态。
  • 阻塞状态
  • 线程池任务应避免 synchronized 或锁竞争,防止 BLOCKED
  • 使用无锁结构(如 ConcurrentHashMap)或异步任务。
  • 中断响应
  • 任务需正确处理 InterruptedException,避免线程卡在 WAITING
  • 示例: java pool.submit(() -> { try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); // 恢复中断状态 } });
  • 线程池配置
  • corePoolSizemaximumPoolSizekeepAliveTime 影响线程状态:
    • corePoolSize 增加 TIMED_WAITINGTERMINATED
    • keepAliveTime 保持线程 WAITING
  • 资源管理
  • 线程池关闭(shutdown())确保线程进入 TERMINATED,释放资源。
  • 避免任务泄漏导致线程卡在 WAITING

7. 面试角度

  • 问“线程池线程有哪些状态”
  • NEW(创建)、RUNNABLE(执行/就绪)、WAITING(核心线程空闲)、TIMED_WAITING(非核心线程空闲)、TERMINATED(终止),BLOCKED 少见。
  • 问“线程池如何管理线程状态”
  • Worker.runWorker() 循环执行任务,BlockingQueue.take()/poll() 控制 WAITING/TIMED_WAITING,中断触发 TERMINATED
  • 问“空闲线程状态”
  • 提核心线程 WAITINGqueue.take()),非核心线程 TIMED_WAITINGqueue.poll(timeout))。
  • 问“BLOCKED 何时出现”
  • 提任务中使用 synchronized 等待锁,线程池设计应避免。
  • 问“线程复用如何实现”
  • 提线程保持 RUNNABLE/WAITING,循环从队列取任务,减少 NEW/TERMINATED
  • 问“如何监控线程状态”
  • Thread.getState()、JMX、ThreadMXBean,举例日志输出。

8. 总结

  • 线程池线程状态
  • NEW:线程创建,未启动。
  • RUNNABLE:执行任务或等待 CPU。
  • WAITING:核心线程空闲,等待任务(queue.take())。
  • TIMED_WAITING:非核心线程空闲,限时等待(queue.poll(timeout))。
  • TERMINATED:任务完成或池关闭。
  • BLOCKED:任务中等待锁(少见)。
  • 状态变迁
  • NEWRUNNABLEWAITING/TIMED_WAITINGRUNNABLETERMINATED
  • 管理机制
  • Worker 封装线程,BlockingQueue 控制等待,ThreadFactory 创建线程,中断触发终止。
  • 面试建议
  • 提 6 种状态、线程池生命周期(创建 → 执行 → 空闲 → 终止)、队列阻塞(take/poll)、避免 BLOCKED,举代码(ThreadPoolExecutor 配置),清晰展示理解。