線程通信是併發編程核心難點,Java通過Object.wait/notify、LockSupport.park/unpark、Condition三套機制實現線程協作。本文系統梳理線程狀態流轉、通信模式與避坑指南。
NEW (新建)
↓ start()
RUNNABLE (可執行) ←→ BLOCKED (阻塞/鎖等待)
↓ wait()/join()/park() ↓ 獲取鎖
WAITING (無限等待) / TIMED_WAITING (超時等待)
↓ notify()/notifyAll()/unpark()/超時
RUNNABLE (重新競爭CPU)
↓ run()結束/異常拋出
TERMINATED (終止)
wait/notify必須持有對象監視器(在synchronized(obj)塊內)
class BoundedBuffer {
private final List buffer = new ArrayList<>();
private final int capacity;
public BoundedBuffer(int capacity) { this.capacity = capacity; }
public synchronized void put(T item) throws InterruptedException {
while (buffer.size() == capacity) { // 條件循環防虛假喚醒
wait();
}
buffer.add(item);
notifyAll(); // 喚醒消費者
}
public synchronized T take() throws InterruptedException {
while (buffer.isEmpty()) {
wait();
}
T item = buffer.remove(0);
notifyAll(); // 喚醒生產者
return item;
}
}
| 方法 | 釋放鎖 | 進入狀態 | 喚醒方式 | 用途 |
|---|---|---|---|---|
sleep(ms) | 否 | TIMED_WAITING | 時間到/中斷 | 定時延遲 |
yield() | 否 | RUNNABLE | 調度器決定 | 禮讓CPU(極少用) |
wait() | 是 | WAITING | notify/中斷 | 條件等待 |
park() | 否 | WAITING | unpark/中斷 | 底層阻塞原語 |
suspend() | 否 | - | resume() | 已棄用(死鎖風險) |
// 當前線程阻塞
LockSupport.park(); // 無限等待
LockSupport.parkNanos(nanos); // 定時等待
LockSupport.parkUntil(deadline); // 截止時間等待
// 喚醒指定線程
LockSupport.unpark(thread); // 許可證機制,不阻塞
特點:不需要持有鎖、基於許可證(最多1個)、不拋InterruptedException(需自檢Thread.interrupted())
class AdvancedBuffer {
private final Lock lock = new ReentrantLock();
private final Condition notFull = lock.newCondition();
private final Condition notEmpty = lock.newCondition();
private final Queue queue = new ArrayDeque<>();
private final int capacity;
public void put(T item) throws InterruptedException {
lock.lock();
try {
while (queue.size() == capacity) notFull.await();
queue.add(item);
notEmpty.signal(); // 精確喚醒消費者
} finally { lock.unlock(); }
}
public T take() throws InterruptedException {
lock.lock();
try {
while (queue.isEmpty()) notEmpty.await();
T item = queue.poll();
notFull.signal(); // 精確喚醒生產者
return item;
} finally { lock.unlock(); }
}
}
優勢:一把鎖綁定多條件隊列、支持公平鎖、可中斷等待awaitUninterruptibly()、超時精確到納秒
// 錯誤:嵌套同步獲取鎖順序不一致
synchronized(lock1) { synchronized(lock2) { ... } } // 線程1
synchronized(lock2) { synchronized(lock1) { ... } } // 線程2 → 死鎖
// 正確:統一全局獲取順序
private static final Object LOCK1 = new Object(), LOCK2 = new Object();
synchronized(LOCK1) { synchronized(LOCK2) { ... } } // 所有線程相同順序
// 或使用tryLock超時避免
if (lock1.tryLock(1, TimeUnit.SECONDS)) {
try { if (lock2.tryLock(1, TimeUnit.SECONDS)) { ... } }
finally { lock1.unlock(); }
}
while(condition) wait();掌握線程狀態機、監視器語義、Condition精確喚醒,是編寫正確高效併發代碼的前提。