Java 併發編程中,synchronized 與 java.util.concurrent.locks.Lock 是兩大核心同步手段。它們功能重疊但設計哲學、性能表現、使用方式截然不同。
| 維度 | synchronized | Lock (ReentrantLock) |
|---|---|---|
| 本質 | JVM 內置關鍵字 | JDK API 級別接口 |
| 鎖釋放 | 自動(塊結束/異常拋出) | 手動 unlock(),必須在 finally 中調用 |
| 性能 | JDK 1.6+ 優化後接近 Lock | 高併發下優勢明顯 |
| 公平性 | 非公平(不可配置) | 可選公平/非公平 |
| 中斷響應 | 不支持 | lockInterruptibly() 支持 |
| 超時等待 | 不支持 | tryLock(timeout) 支持 |
| 條件變量 | wait/notify 綁定對象鎖 | Condition 可多條件精準控制 |
// 鎖定當前實例
synchronized (this) { ... }
// 鎖定類對象(等同 static synchronized 方法)
synchronized (MyClass.class) { ... }
// 鎖定任意對象
synchronized (sharedObject) { ... }
class Test {
public static User user = null; // 靜態字段,屬於類
// 實例方法鎖定 this,多個實例互不阻塞!
public synchronized void add(User u) {
user = u;
Dao.save(user); // 競態條件:線程1尚未save,線程2已修改user
}
}
兩個線程分別 new Test(),調用 add() 時鎖的是不同實例,無法同步訪問 static user。
public static synchronized void add(User u) { ... } // 鎖定 Test.class
class Test {
public static User user = null;
private static final Lock lock = new ReentrantLock();
public void add(User u) {
lock.lock();
try {
user = u;
Dao.save(user);
} finally {
lock.unlock(); // 必須釋放!
}
}
}
ReentrantLock 為靜態字段,所有實例共享同一把鎖,等效於 static synchronized,但提供更精細控制(可中斷、超時、公平鎖、多 Condition)。
synchronized 是「開箱即用」的同步利器,現代 JVM 已極度優化;Lock 是「專業級工具箱」,解決 synchronized 無法覆蓋的進階場景。理解雙方本質,按需選型,才是併發編程的正道。