首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java鎖機制深度解析:synchronized 與 Lock 的核心差異與最佳實踐

     編輯:Java 相關知識

核心異同概覽

維度synchronizedLock (java.util.concurrent.locks.Lock)
功能覆蓋基礎同步涵蓋 synchronized 所有功能並擴展更多特性
線程語義隱式獲取/釋放鎖顯式 lock()/unlock(),需在 finally 中釋放
精確控制不支援中斷、超時、公平鎖等支援可中斷、超時等待、公平/非公平鎖、條件變量
效能表現JVM 優化後效能優異,低競爭下極快高競爭下吞吐量通常優於 synchronized

synchronized 核心機制

對象鎖與可重入計數

每個 Java 對象天生持有一把監視器鎖。JVM 維護一個計數器:

  • 線程首次獲取鎖 → 計數 = 1
  • 同一線程重複獲取 → 計數遞增
  • 退出 synchronized 區塊 → 計數遞減
  • 計數歸零 → 鎖完全釋放,其他線程可競爭

同步塊作用範圍

當多個同步塊鎖定同一對象(如 synchronized(this))時,無論位於不同方法,線程間均互斥執行。若鎖定不同對象實例,則無同步效果。

靜態方法同步陷阱

class Test {
    public static User user = null;
    public synchronized void add(User u) {  // 鎖的是 Test.class 實例?錯!鎖的是 this
        user = u;
        Dao.save(user);
    }
}

若兩線程分別 new Test(),則持有不同鎖,user 為 static 共享變量將發生競態。修正方式:

  • 改為 static synchronized void add(...) 鎖定 Class 對象
  • 或
  • 引入 ReentrantLock 實現跨實例同步

Lock 實戰範例

class Test {
    public static User user = null;
    private final Lock lock = new ReentrantLock();

    public void add(User u) {
        lock.lock();
        try {
            user = u;
            Dao.save(user);
        } finally {
            lock.unlock();  // 必須在 finally 釋放
        }
    }
}

此寫法無論 new 多少個 Test 實例,均共享同一把鎖,等效於 static synchronized,但提供更豐富的鎖操作語義。

選型建議

  • 簡單同步、低競爭 → synchronized(語法簡潔,JVM 深度優化)
  • 需可中斷、超時、公平鎖、多條件變量 → Lock
  • 高併發寫入場景 → ReentrantLock 通常吞吐更高
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved