线程池创建线程的状态
概述
- 定义:
- 线程池(
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
| | | | |
创建 启动并执行 空闲等待任务 再次执行任务 终止
- 创建:
NEW
→RUNNABLE
(调用start()
)。 - 执行任务:
RUNNABLE
。 - 空闲等待:
- 核心线程:
WAITING
(queue.take()
)。 - 非核心线程:
TIMED_WAITING
(queue.poll(timeout)
)。 - 再次执行:
WAITING
/TIMED_WAITING
→RUNNABLE
(获取任务)。 - 终止:
RUNNABLE
→TERMINATED
(任务完成或池关闭)。 - 特殊:
RUNNABLE
→BLOCKED
(任务中等待锁,少见)。
状态图:
+---------+
| 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
。 - 线程复用:
- 线程池通过复用线程(保持
RUNNABLE
或WAITING
)减少NEW
和TERMINATED
的开销。
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(); // 恢复中断状态 } });
- 线程池配置:
corePoolSize
、maximumPoolSize
、keepAliveTime
影响线程状态:- 小
corePoolSize
增加TIMED_WAITING
和TERMINATED
。 - 长
keepAliveTime
保持线程WAITING
。
- 小
- 资源管理:
- 线程池关闭(
shutdown()
)确保线程进入TERMINATED
,释放资源。 - 避免任务泄漏导致线程卡在
WAITING
。
7. 面试角度
- 问“线程池线程有哪些状态”:
- 提
NEW
(创建)、RUNNABLE
(执行/就绪)、WAITING
(核心线程空闲)、TIMED_WAITING
(非核心线程空闲)、TERMINATED
(终止),BLOCKED
少见。 - 问“线程池如何管理线程状态”:
- 提
Worker.runWorker()
循环执行任务,BlockingQueue.take()
/poll()
控制WAITING
/TIMED_WAITING
,中断触发TERMINATED
。 - 问“空闲线程状态”:
- 提核心线程
WAITING
(queue.take()
),非核心线程TIMED_WAITING
(queue.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:任务中等待锁(少见)。
- 状态变迁:
NEW
→RUNNABLE
→WAITING
/TIMED_WAITING
→RUNNABLE
→TERMINATED
。- 管理机制:
Worker
封装线程,BlockingQueue
控制等待,ThreadFactory
创建线程,中断触发终止。- 面试建议:
- 提 6 种状态、线程池生命周期(创建 → 执行 → 空闲 → 终止)、队列阻塞(
take
/poll
)、避免BLOCKED
,举代码(ThreadPoolExecutor
配置),清晰展示理解。