多線程並發訪問共享可變數據時,會出現原子性違背、可見性失效、有序性破壞,導致數據不一致。同步機制通過互斥鎖與內存屏障保證:
synchronized(lockObject) {
// 臨界區:操作共享數據
}
lockObject 必須為同一對象(通常用共享數據本身、this、類對象、專用鎖對象);public synchronized void method() { ... } // 鎖 this
public static synchronized void staticMethod() { ... } // 鎖 Class 對象
this 或 Class 作為鎖;屬於 Object 方法,必須在同步塊/方法內調用,否則拋 IllegalMonitorStateException。
| 方法 | 作用 | 關鍵點 |
|---|---|---|
wait() | 釋放鎖,進入等待集合,阻塞當前線程 | 可被 notify/notifyAll 或中斷喚醒 |
wait(long timeout) | 超時自動喚醒 | 超時返回不拋異常,需重新檢查條件 |
notify() | 喚醒任一等待線程 | 喚醒線程需重新競爭鎖 |
notifyAll() | 喚醒所有等待線程 | 推薦使用,避免信號丟失導致死鎖 |
class Buffer {
private final List<Integer> queue = new ArrayList<>();
private final int capacity;
public synchronized void put(int v) throws InterruptedException {
while (queue.size() == capacity) wait(); // 滿等待
queue.add(v);
notifyAll(); // 喚醒消費者
}
public synchronized int take() throws InterruptedException {
while (queue.isEmpty()) wait(); // 空等待
int v = queue.remove(0);
notifyAll(); // 喚醒生產者
return v;
}
}
ReentrantLock 提供比 synchronized 更豐富的功能:
lockInterruptibly();new ReentrantLock(true);lock.newCondition() 區分不同等待隊列(如 notEmpty/notFull),精準喚醒;tryLock()/tryLock(timeout, unit)。final ReentrantLock lock = new ReentrantLock();
final Condition notEmpty = lock.newCondition();
final Condition notFull = lock.newCondition();
// 入隊
lock.lock();
try {
while (count == items.length) notFull.await();
insert(x);
notEmpty.signal();
} finally { lock.unlock(); }
// 出隊
lock.lock();
try {
while (count == 0) notEmpty.await();
return extract();
notFull.signal();
} finally { lock.unlock(); }
ConcurrentHashMap、CopyOnWriteArrayList、BlockingQueue 等無鎖/細粒度鎖實現;final 字段、String、LocalDate 天然線程安全,無需同步;tryLock 超時退出、減少嵌套鎖;i++ 仍需同步)。