java.util.concurrent.locks.Condition 是 JDK 1.5 引入的線程協作工具,配合 Lock 使用,提供 await()/signal()/signalAll(),功能對標 Object.wait/notify/notifyAll 但更安全、更靈活、支持多條件隊列。本文對比兩者,給出生產消費完整實現。
| 特性 | Object Monitor | Condition |
|---|---|---|
| 綁定鎖 | 隱式 this / synchronized 鎖 | 顯式 Lock 實例(可多條件共享一把鎖) |
| 等待方法 | wait() | await() / awaitUninterruptibly() / awaitNanos() |
| 喚醒方法 | notify() / notifyAll() | signal() / signalAll() |
| 多條件隊列 | 不支持(單一等待集) | 支持(一把鎖創建多個 Condition) |
| 可中斷等待 | 不支持 | 支持 await() 拋 InterruptedException |
| 公平性 | 非公平 | 可配合 ReentrantLock(true) 實現公平 |
| 檢查鎖狀態 | 無 | 必须在 lock.lock() 與 unlock() 之間調用 |
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class ConditionDemo {
private final Object[] queue = new Object[100];
private int readIndex = 0, writeIndex = 0, dataLen = 0;
private final Lock lock = new ReentrantLock();
private final Condition notFull = lock.newCondition(); // 生產者等待條件
private final Condition notEmpty = lock.newCondition(); // 消費者等待條件
// 生產
public void write(Object obj) {
lock.lock();
try {
while (dataLen >= queue.length) { // 用 while 防虛假喚醒
System.out.println("隊列滿,生產者等待...");
notFull.await();
}
queue[writeIndex] = obj;
writeIndex = (writeIndex + 1) % queue.length;
dataLen++;
notEmpty.signal(); // 喚醒一個消費者
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
lock.unlock();
}
}
// 消費
public Object read() {
lock.lock();
try {
while (dataLen <= 0) {
System.out.println("隊列空,消費者等待...");
notEmpty.await();
}
Object obj = queue[readIndex];
readIndex = (readIndex + 1) % queue.length;
dataLen--;
notFull.signal(); // 喚醒一個生產者
return obj;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
} finally {
lock.unlock();
}
}
// 測試
public static void main(String[] args) {
final ConditionDemo demo = new ConditionDemo();
new Thread(() -> {
for (int i = 0; i < 1000; i++) demo.write(i);
}, "Producer").start();
new Thread(() -> {
while (true) {
Object obj = demo.read();
if (obj != null) System.out.println("消費: " + obj);
}
}, "Consumer").start();
}
}
while (condition) await() 防止虛假喚醒(JVM 規範允許無通知喚醒)。signal();多生產/多消費建議 signalAll() 避免信號丟失導致線程饑餓。lock.lock() → try → finally lock.unlock(),否則死鎖。await() 拋 InterruptedException 時需恢復中斷狀態 Thread.currentThread().interrupt()。ArrayBlockingQueue 內部即用 Condition)。ReentrantReadWriteLock 內部有读/写 Condition)。DelayQueue 使用 Condition 等待最近任務到期)。