Java 5 引入 java.util.concurrent.locks.Lock 介面,提供比 synchronized 更靈活的同步控制:
lock()/unlock(),支援非塊結構(跨方法加解鎖)。lockInterruptibly(),等待鎖時響應中斷。tryLock()/tryLock(timeout, unit),獲取失敗立即返回或超時返回。new ReentrantLock(true) 公平鎖,避免饑餓。newCondition() 實現精細化等待/通知(vs Object.wait/notify 單一條件)。同一線程可重複獲取同一把鎖,內部維護 state 計數器,lock() 增、unlock() 減,歸零釋放。必須配對調用,建議放在 finally 中保證釋放。
public class Account {
private final ReentrantLock lock = new ReentrantLock(); // 最終引用,不可變
private String accountNo;
private double balance;
public Account(String accountNo, double balance) {
this.accountNo = accountNo;
this.balance = balance;
}
public void draw(double amount) {
lock.lock(); // 1. 加鎖
try {
if (balance >= amount) {
System.out.println(Thread.currentThread().getName() + " 取款成功:" + amount);
Thread.sleep(1); // 模擬耗時
balance -= amount;
System.out.println("\t餘額:" + balance);
} else {
System.out.println(Thread.currentThread().getName() + " 取款失敗:餘額不足");
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 保留中斷狀態
} finally {
lock.unlock(); // 2. 釋放鎖(必須在 finally)
}
}
// equals/hashCode 基於 accountNo
}
public class DrawThread extends Thread {
private Account account;
private double amount;
public DrawThread(String name, Account account, double amount) {
super(name); this.account = account; this.amount = amount;
}
@Override public void run() { account.draw(amount); }
}
public class TestDraw {
public static void main(String[] args) {
Account acct = new Account("1234567", 1000);
new DrawThread("甲", acct, 800).start();
new DrawThread("乙", acct, 800).start();
}
}
甲 取款成功:800.0
餘額:200.0
乙 取款失敗:餘額不足
兩線程共享同一 Account 實例 → 共享同一 ReentrantLock → 同一時刻僅一線程進入 draw() 臨界區 → 餘額檢查與扣減原子化。
| 方法 | 場景 |
|---|---|
tryLock() | 非阻塞嘗試,失敗立即執行降級邏輯(如顯示「系統繁忙」)。 |
tryLock(3, TimeUnit.SECONDS) | 限時等待,避免無限阻塞,超時走補償流程。 |
lockInterruptibly() | 可中斷等待,支援取消操作(如用戶點「取消」按鈕)。 |
newCondition() | 生產者/消費者模型:notFull.await()/notEmpty.signal()。 |
isHeldByCurrentThread() | 診斷鎖持有狀態,防死鎖調試。 |