线程状态,BLOCKED和WAITING有什么区别
线程状态中,BLOCKED 和 WAITING 是两种不同的阻塞状态,它们的区别主要体现在线程阻塞的原因和等待方式上。下面帮你详细解析这两者的区别和应用场景。
一、线程状态简述
Java 中线程的状态由 Thread.State 枚举表示,主要状态包括:
- NEW:新建,线程还未启动
- RUNNABLE:可运行,线程正在运行或等待 CPU 时间片
- BLOCKED:阻塞,等待获取监视器锁(monitor lock)
- WAITING:无限期等待,等待另一个线程显式通知
- TIMED_WAITING:限时等待,等待指定时间后自动唤醒
- TERMINATED:终止,线程执行完成或退出
二、BLOCKED 和 WAITING 的详细区别
| 特性 | BLOCKED | WAITING |
|---|---|---|
| 等待原因 | 等待进入同步块或方法,争抢对象锁 | 等待其他线程显式通知(如 wait()、join()) |
| 触发方式 | 线程尝试获得对象锁失败进入阻塞队列 | 线程调用无超时等待方法进入等待状态 |
| 恢复条件 | 获得锁后恢复运行 | 被其他线程 notify() 或 notifyAll() 唤醒,或调用 interrupt() |
| 等待时间 | 直到获得锁,时间不确定 | 无限等待,直到收到通知或中断 |
| 典型场景 | 进入 synchronized 代码块或方法时,锁被占用 | 调用 Object.wait() 或 Thread.join() 等等待线程操作 |
三、具体示例对比
1. BLOCKED 示例
public class BlockedDemo {
private final Object lock = new Object();
public void method() {
synchronized (lock) {
try {
Thread.sleep(5000); // 模拟占用锁5秒
} catch (InterruptedException e) {}
}
}
public static void main(String[] args) {
BlockedDemo demo = new BlockedDemo();
new Thread(() -> demo.method(), "线程-1").start();
new Thread(() -> {
System.out.println(Thread.currentThread().getName() + " 尝试获取锁");
demo.method(); // 这里如果锁被占用,线程会进入 BLOCKED 状态
}, "线程-2").start();
}
}
线程-2在锁被线程-1占用时进入 BLOCKED 状态,等待锁释放。
2. WAITING 示例
public class WaitingDemo {
public static void main(String[] args) throws InterruptedException {
Object lock = new Object();
Thread t1 = new Thread(() -> {
synchronized (lock) {
try {
System.out.println("线程等待通知...");
lock.wait(); // 进入 WAITING 状态,等待通知
System.out.println("线程被唤醒");
} catch (InterruptedException e) {
System.out.println("线程被中断");
}
}
});
t1.start();
Thread.sleep(2000);
synchronized (lock) {
lock.notify(); // 唤醒等待线程
}
}
}
- 线程调用
wait()后进入 WAITING 状态,等待其他线程调用notify()唤醒。
四、状态转换流程示意
RUNNABLE
|
|(尝试进入 synchronized 代码块,锁被占用)
↓
BLOCKED (等待锁)
|
|(获得锁)
↓
RUNNABLE
---
RUNNABLE
|
|(调用 wait() 或 join() 等无超时等待方法)
↓
WAITING
|
|(其他线程调用 notify()/interrupt())
↓
RUNNABLE
五、总结对比
| 方面 | BLOCKED | WAITING |
|---|---|---|
| 阻塞原因 | 竞争对象锁 | 等待显式通知 |
| 是否依赖锁 | 是 | 否 |
| 等待时长 | 不定,直到获得锁 | 不定,直到通知或中断 |
| 进入方式 | 尝试进入 synchronized 块时失败 | 调用 wait()、join() 等 |
| 唤醒方式 | 获得锁即恢复 | 其他线程调用 notify()/interrupt() |
| 典型使用场景 | 同步锁竞争 | 线程间通信和协调 |
六、参考资料
- Java官方文档 – Thread.State
- 《Java并发编程实战》Chapter 3 — 线程状态与同步
- Oracle Java Tutorials – Thread States
更多详细内容请关注其他相关文章!