1. Java线程状态模型深度解析
在Java并发编程中,线程状态是理解程序行为的关键指标。作为一名长期从事Java开发的工程师,我经常需要通过线程状态来诊断各种并发问题。本文将基于JDK官方定义,结合多年实战经验,深入剖析Java线程的六种状态及其转换机制。
1.1 线程状态枚举定义
Java在java.lang.Thread类中明确定义了线程的六种状态:
java复制public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}
这六种状态构成了Java线程的完整生命周期。值得注意的是,这些状态是JVM层面的抽象,与操作系统原生线程状态存在映射关系但不等同。
1.2 状态详解与核心特征
1.2.1 NEW(新建状态)
当线程对象通过new Thread()创建但尚未调用start()方法时,线程处于NEW状态。此时:
- 尚未分配系统资源
- 未与操作系统原生线程关联
- 不能执行任何代码
典型创建方式:
java复制Thread t = new Thread(() -> System.out.println("Hello"));
System.out.println(t.getState()); // 输出NEW
重要提示:直接调用线程对象的run()方法不会改变状态,必须通过start()方法启动线程。
1.2.2 RUNNABLE(可运行状态)
调用start()方法后,线程进入RUNNABLE状态。这个状态实际上包含两种子状态:
- Ready:线程已准备好,等待CPU时间片
- Running:线程正在CPU上执行
JVM不区分这两种子状态,统一表示为RUNNABLE。这也是为什么我们看到CPU使用率高时,很多线程都显示为RUNNABLE状态。
示例:
java复制Thread t = new Thread(() -> {
while(true) {/* 空循环 */}
});
t.start();
Thread.sleep(10);
System.out.println(t.getState()); // 输出RUNNABLE
1.2.3 BLOCKED(阻塞状态)
线程在等待进入synchronized同步块或方法时,如果锁已被其他线程持有,则会进入BLOCKED状态。这是Java线程状态中唯一由synchronized关键字触发的状态。
关键特征:
- 仅由synchronized引起
- 不消耗CPU资源
- 锁释放后会竞争进入RUNNABLE状态
示例:
java复制Object lock = new Object();
Thread t1 = new Thread(() -> {
synchronized(lock) {
try { Thread.sleep(5000); }
catch (InterruptedException e) {}
}
});
Thread t2 = new Thread(() -> {
synchronized(lock) {
System.out.println("t2 acquired lock");
}
});
t1.start();
Thread.sleep(100); // 确保t1先获取锁
t2.start();
Thread.sleep(100);
System.out.println("t2 state: " + t2.getState()); // 输出BLOCKED
1.2.4 WAITING(无限等待状态)
线程调用以下方法之一会进入WAITING状态:
- Object.wait()
- Thread.join()
- LockSupport.park()
关键特征:
- 必须被显式唤醒(notify/notifyAll/unpark等)
- 不消耗CPU资源
- wait()会释放对象监视器锁
示例:
java复制Object obj = new Object();
Thread waiter = new Thread(() -> {
synchronized(obj) {
try {
obj.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
waiter.start();
Thread.sleep(100);
System.
