BLOCKED vs WAIT
简短结论先说清楚:
-
BLOCKED :线程尝试进入
synchronized获取对象监视器(锁)但失败 时的状态 ------ 它在等待 获得锁 (并不持有锁)。 -
WAITING (这里特指
Object.wait()导致的等待):线程主动调用wait(),会释放锁 并进入等待队列,直到被notify/notifyAll(或中断)唤醒,然后再去竞争锁并继续执行。
下面给你一段 Java 程序,分别演示两者的区别,并在关键时刻打印线程状态(Thread.getState())。
示例代码
java
public class BlockedVsWaitDemo {
public static void main(String[] args) throws InterruptedException {
System.out.println("=== BLOCKED 演示 ===");
blockedDemo();
System.out.println("\n=== WAITING (wait) 演示 ===");
waitDemo();
}
// 场景:一个线程持有锁并 sleep(模拟长时间占用),另一个线程尝试进入同一 synchronized -> BLOCKED
private static void blockedDemo() throws InterruptedException {
final Object lock = new Object();
Thread holder = new Thread(() -> {
synchronized (lock) {
System.out.println("[Holder] acquired lock, going to sleep 3s");
try { Thread.sleep(3000); } catch (InterruptedException ignored) {}
System.out.println("[Holder] done sleeping, releasing lock");
}
}, "Holder");
Thread blocker = new Thread(() -> {
System.out.println("[Blocker] trying to enter synchronized block...");
synchronized (lock) {
System.out.println("[Blocker] acquired lock!");
}
}, "Blocker");
holder.start();
// 确保 holder 先占到锁
Thread.sleep(100);
blocker.start();
// 等一点让 blocker 尝试获取锁,然后打印其状态
Thread.sleep(100);
System.out.println("[Main] Blocker state (expect BLOCKED): " + blocker.getState());
// 等待结束
holder.join();
blocker.join();
}
// 场景:一个线程 synchronized 后调用 wait() -> 释放锁并进入 WAITING;
// 另一个线程 synchronized 并 notify() 唤醒它。
private static void waitDemo() throws InterruptedException {
final Object lock = new Object();
Thread waiter = new Thread(() -> {
synchronized (lock) {
System.out.println("[Waiter] acquired lock, calling wait()");
try {
lock.wait(); // 释放锁,进入 WAITING
} catch (InterruptedException e) {
System.out.println("[Waiter] interrupted");
}
System.out.println("[Waiter] resumed after wait(), continuing...");
}
}, "Waiter");
Thread notifier = new Thread(() -> {
try { Thread.sleep(500); } catch (InterruptedException ignored) {}
synchronized (lock) {
System.out.println("[Notifier] acquired lock, calling notify()");
lock.notify(); // 唤醒 waiter(waiter 进入可竞争状态)
System.out.println("[Notifier] notify done, will release lock soon");
}
}, "Notifier");
waiter.start();
// 等一点确保 waiter 已经进入 wait()
Thread.sleep(200);
System.out.println("[Main] Waiter state (expect WAITING): " + waiter.getState());
notifier.start();
// 给一些时间让 notify 执行:在 notify 之后,waiter 会变为 BLOCKED(等待重新获得锁)
Thread.sleep(100);
System.out.println("[Main] Waiter state maybe BLOCKED (waiting to reacquire lock): " + waiter.getState());
waiter.join();
notifier.join();
}
}
预期输出(大致顺序,具体时间会有微差)
java
=== BLOCKED 演示 ===
[Holder] acquired lock, going to sleep 3s
[Blocker] trying to enter synchronized block...
[Main] Blocker state (expect BLOCKED): BLOCKED
[Holder] done sleeping, releasing lock
[Blocker] acquired lock!
=== WAITING (wait) 演示 ===
[Waiter] acquired lock, calling wait()
[Main] Waiter state (expect WAITING): WAITING
[Notifier] acquired lock, calling notify()
[Notifier] notify done, will release lock soon
[Main] Waiter state maybe BLOCKED (waiting to reacquire lock): BLOCKED
[Waiter] resumed after wait(), continuing...
重点说明:
-
在 BLOCKED 演示 中,
Blocker因为Holder持有锁而处于BLOCKED。 -
在 WAITING 演示 中,当
waiter调用lock.wait()后它会 释放锁并进入WAITING状态(因此notifier能拿到锁并notify())。notify()把 waiter 从等待队列中唤醒,但 唤醒后 waiter 要先重新抢锁 ------ 在notifier释放锁之前,waiter 会处于 等待抢锁 的阶段,这时在Thread.getState()上通常看到的是BLOCKED(因为它在等待进入 synchronized 块重新获得监视器)。一旦它成功拿到锁,状态回到RUNNABLE并继续执行。
总结对比(简洁版)
-
触发方式
-
BLOCKED:线程在尝试进入
synchronized(obj)时,目标监视器已被其他线程持有 → 进入 BLOCKED。 -
WAITING:线程主动调用
obj.wait()(或被join()/LockSupport.park()等) → 进入 WAITING。
-
-
锁的持有情况
-
BLOCKED:没有持有锁,正在等待获取锁。
-
WAITING:调用
wait()时会 释放锁(这是 wait 的关键行为),线程本身进入等待队列。
-
-
唤醒方式
-
BLOCKED:不是被 notify 唤醒;只是当某个线程释放锁后,调度器允许它获取锁。
-
WAITING:需要
notify()/notifyAll()(或中断/超时)来唤醒,然后再去竞争锁。
-
-
常见用途
-
BLOCKED:自然发生(竞争同步块)。
-
WAITING:用于线程间协作(生产者/消费者等)。
-