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

Java synchronized 方法同步深度解析:鎖對象、靜態與非靜態、同步塊最佳實踐

     編輯:Java 相關知識

核心原理:每個對象一把鎖

Java 為每個對象關聯一把監視器鎖。synchronized 方法/塊本質是獲取鎖 → 執行臨界區 → 釋放鎖。同一把鎖同一時間只能被一個線程持有。

兩種同步形式對比

形式鎖對象作用範圍字節碼指令
同步實例方法this整個方法體ACC_SYNCHRONIZED 標誌
同步靜態方法Class對象整個方法體ACC_SYNCHRONIZED 標誌
同步代碼塊括號內表達式大括號內代碼monitorenter/monitorexit

非靜態方法同步:this 鎖

public class Test {
    public void method1() { synchronized(this) { /* 臨界區 */ } }
    public synchronized void method2() { /* 臨界區 */ }
    // method1 與 method2 互斥:共用 this 鎖
}

內部類場景:內部類 this 指向內部類實例。若需與外部類同步,用 OuterClass.this:

class Outer {
    class Inner {
        void method3() { synchronized(Outer.this) { } } // 鎖住外部類實例
    }
}

靜態方法同步:Class 鎖

靜態方法無 this,必須用類字面量或 getClass():

public class Test {
    public static void method1() { synchronized(Test.class) { } }
    public static synchronized void method2() { }
    // 兩方法互斥:共用 Test.class 鎖
}

跨類同步:不同類的靜態方法可共享一把 Class 鎖(如 synchronized(SharedClass.class))。

關鍵規則與陷阱

  1. 靜態 vs 非靜態互不干擾:一線程執行靜態同步方法,另一線程可同時執行同對象的非靜態同步方法(鎖不同)。若共享數據,必須統一鎖策略。
  2. 同步塊異常自動釋放:正常退出或拋出異常,JVM 保證 monitorexit 執行。
  3. 遞歸重入:同一線程可重複獲取同一把鎖(計數器機制)。
  4. 性能代價:synchronized 涉及用戶態/內核態切換、上下文切換,僅在真正併發寫入共享數據時使用。

最佳實踐:縮小臨界區

// ❌ 差:整個方法同步,包含耗時 IO
public synchronized void updateAndLog(Data d) {
    compute(d); saveToDB(d); log.info("done");
}

// ✅ 好:只保護共享數據修改
public void updateAndLog(Data d) {
    Data copy;
    synchronized(this) { copy = compute(d); } // 臨界區極小
    saveToDB(copy); log.info("done"); // 耗時操作移出
}

進階:鍵對象選擇原則

  • ✅ private final Object lock = new Object();(專用鎖,封裝性最好)
  • ✅ this / ClassName.class(簡單場景)
  • ❌ String、包裝類、常量池對象(可能被無關代碼共享)
  • ❌ getClass() 於繼承體系中(子類獲取的是子類 Class,破壞同步語義)

總結

掌握 synchronized 的鎖對象語義、靜態/非靜態差異、代碼塊粒度控制,是編寫正確高效併發代碼的基礎。實戰中:優先私有 final 鎖對象、縮小臨界區、避免跨類共享鎖,複雜場景轉用 java.util.concurrent 工具類。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved