wait()、notify()、notifyAll() 是條件隊列的固有方法防止競態條件:
// 生產者邏輯 if (buffer.full()) wait(); // 1.1 檢查條件 → 1.2 進入等待 // 消費者邏輯 buffer.take(); // 2.1 消費 buffer.notFull(); // 2.2 狀態變更 notifyAll(); // 2.3 通知
無鎖時,可能發生:1.1 → 2.1 → 2.2 → 2.3 → 1.2,導致生產者永久等待(通知丟失)。
synchronized 保證「檢查-等待」與「修改-通知」互斥執行。
| 方法 | 語義 | 鎖行為 | 拋出異常 |
|---|---|---|---|
| wait() | 釋放鎖、進入等待集、阻塞直到被喚醒/中斷/超時 | 釋放當前對象鎖 | IllegalMonitorStateException (無鎖)、InterruptedException |
| wait(long timeout) | 帶超時等待 | 同上 | 同上 |
| notify() | 隨機喚醒一個等待線程 | 不釋放鎖,喚醒線程需重新競爭鎖 | IllegalMonitorStateException |
| notifyAll() | 喚醒所有等待線程 | 同上 | 同上 |
public class Buffer {
private int value;
private boolean hasValue = false;
public synchronized void put(int value) {
while (hasValue) { // while 防虛假喚醒
try { wait(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
}
this.value = value;
hasValue = true;
System.out.println("生產: " + value);
notifyAll(); // 喚醒消費者
}
public synchronized int take() {
while (!hasValue) {
try { wait(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
}
hasValue = false;
System.out.println("消費: " + value);
notifyAll(); // 喚醒生產者
return value;
}
}
public class Producer implements Runnable {
private Buffer buffer;
public Producer(Buffer buffer) { this.buffer = buffer; }
@Override public void run() {
for (int i = 0; i < 10; i++) buffer.put(i);
}
}
public class Consumer implements Runnable {
private Buffer buffer;
public Consumer(Buffer buffer) { this.buffer = buffer; }
@Override public void run() {
for (int i = 0; i < 10; i++) buffer.take();
}
}
public class Main {
public static void main(String[] args) {
Buffer buffer = new Buffer();
new Thread(new Producer(buffer), "生產者").start();
new Thread(new Consumer(buffer), "消費者").start();
}
}
public class AlternatePrinter implements Runnable {
private int number;
private Object lock;
private volatile int turn; // 0: 線程1, 1: 線程2
public AlternatePrinter(int number, Object lock, int turn) {
this.number = number;
this.lock = lock;
this.turn = turn;
}
@Override
public void run() {
synchronized (lock) {
for (int i = 0; i < 5; i++) {
while (turn != (number == 1 ? 0 : 1)) {
try { lock.wait(); } catch (InterruptedException e) { return; }
}
System.out.println(Thread.currentThread().getName() + ": " + number);
turn = 1 - turn; // 切換輪次
lock.notifyAll();
}
}
}
public static void main(String[] args) {
Object lock = new Object();
new Thread(new AlternatePrinter(1, lock, 0), "T1").start();
new Thread(new AlternatePrinter(2, lock, 1), "T2").start();
}
}
while 迴圈中調用 wait(),防虛假喚醒notifyAll(),避免單喚醒導致信號丟失(除非確定單一條件)java.util.concurrent:BlockingQueue、CountDownLatch、CyclicBarrier、Semaphore、Lock + Conditionwait/notify 僅用於底層框架構建或極簡場景,業務代碼盡量避免