多線程共享可變狀態時,複合操作(檢查-執行、讀取-修改-寫入)的非原子性導致競態條件。同步機制確保原子性、可見性、有序性。
private final Lock lock = new ReentrantLock();
public void safeMethod() {
lock.lock();
try {
// 臨界區
} finally {
lock.unlock(); // 必須在 finally 釋放
}
}
public class Bank {
private final double[] accounts;
private final Lock bankLock = new ReentrantLock();
private final Condition sufficientFunds = bankLock.newCondition();
public Bank(int n, double initialBalance) {
accounts = new double[n];
Arrays.fill(accounts, initialBalance);
}
public void transfer(int from, int to, double amount)
throws InterruptedException {
bankLock.lock();
try {
while (accounts[from] < amount) {
sufficientFunds.await(); // 釋放鎖並等待
}
accounts[from] -= amount;
accounts[to] += amount;
sufficientFunds.signalAll(); // 喚醒所有等待線程
} finally {
bankLock.unlock();
}
}
}
public synchronized void transfer(int from, int to, double amount)
throws InterruptedException {
while (accounts[from] < amount) wait();
accounts[from] -= amount;
accounts[to] += amount;
notifyAll();
}
public void transfer(int from, int to, double amount) {
synchronized (this) { // 或鎖專用對象
// 臨界區
}
}
| synchronized | Lock + Condition |
|---|---|
| 同步方法/塊 | lock.lock() / unlock() |
| wait() | condition.await() |
| notify() | condition.signal() |
| notifyAll() | condition.signalAll() |
| 單一條件隊列 | 多條件隊列 |
利用非線程安全對象的內建鎖保護複合操作:
public void transfer(Vector accounts, int from, int to, double amount) {
synchronized (accounts) { // 鎖住 Vector 實例
accounts.set(from, accounts.get(from) - amount);
accounts.set(to, accounts.get(to) + amount);
}
}
警告:脆弱、洩露實現細節、難維護。優先使用 `java.util.concurrent` 線程安全集合(`CopyOnWriteArrayList`、`ConcurrentHashMap`、阻塞隊列)。
| 工具類 | 用途 | 核心方法 |
|---|---|---|
| CountDownLatch | 一組線程等待計數歸零 | countDown(), await() |
| CyclicBarrier | 線程組相互等待屏障點 | await(), barrierAction |
| Semaphore | 控制並發訪問許可證數 | acquire(), release() |
| Exchanger | 兩線程交換數據 | exchange(V) |
| Phaser | 階段性同步,支援動態註冊 | arriveAndAwaitAdvance() |
// 錯誤:不同順序獲取鎖
Thread 1: lock(A) → lock(B)
Thread 2: lock(B) → lock(A)
// 正確:固定順序
private static final Object LOCK1 = new Object(), LOCK2 = new Object();
void method1() { synchronized(LOCK1) { synchronized(LOCK2) { ... } } }
void method2() { synchronized(LOCK1) { synchronized(LOCK2) { ... } } }