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

Java synchronized 關鍵字深度解析:四種用法、鎖升級與最佳實踐

     編輯:Java 相關知識

synchronized 核心語義

synchronized 是 Java 關鍵字,用於保證同一時刻最多只有一個線程執行某段代碼,實現互斥同步。它提供了隱式的鎖機制,由 JVM 自動獲取和釋放。

四種使用方式詳解

1. 修飾實例方法 —— 對象鎖

public synchronized void instanceMethod() {
    // 同一時刻僅一個線程能進入當前對象的所有同步實例方法
}
  • 鎖對象:this (當前實例)
  • 同一對象的不同同步實例方法互斥
  • 不同實例互不干擾

2. 修飾靜態方法 —— 類鎖

public static synchronized void staticMethod() {
    // 同一時刻僅一個線程能進入該類的所有同步靜態方法
}
  • 鎖對象:CurrentClass.class (Class 對象)
  • 所有實例共享同一把鎖
  • 與實例方法鎖互不干擾 (鎖對象不同)

3. 同步代碼塊 (this) —— 對象鎖精細控制

public void method() {
    // 非同步代碼...
    synchronized (this) {
        // 同步代碼 - 鎖住當前對象
    }
    // 非同步代碼...
}
  • 縮小同步範圍,提高並發度
  • 鎖對象:this

4. 同步代碼塊 (自定義對象) —— 細粒度鎖

public class FineGrainedLock {
    private final Object lockA = new Object();
    private final Object lockB = new Object();
    private Resource resourceA, resourceB;

    public void operateA() {
        synchronized (lockA) { // 僅鎖資源 A
            // 訪問 resourceA
        }
    }

    public void operateB() {
        synchronized (lockB) { // 僅鎖資源 B
            // 訪問 resourceB
        }
    }

    public void operateBoth() {
        synchronized (lockA) {
            synchronized (lockB) { // 雙重鎖,注意死鎖風險
                // 同時訪問 A 和 B
            }
        }
    }
}
  • 不同資源用不同鎖,實現細粒度並發控制
  • 零長度 byte 數組 new byte[0] 比 new Object() 更節省內存 (3 vs 7 字節碼)

鎖對象總結表

用法鎖對象作用範圍
同步實例方法this當前實例所有同步實例方法
同步靜態方法ClassName.class該類所有同步靜態方法
synchronized(this)this代碼塊內容
synchronized(customObj)customObj代碼塊內容
synchronized(ClassName.class)ClassName.class代碼塊內容

JVM 鎖優化機制 (Java 6+)

  1. 偏向鎖:無競爭時,鎖偏向首個獲取線程,後續進出無 CAS 開銷
  2. 輕量級鎖:輕度競爭,CAS 操作替代互斥量
  3. 重量級鎖:激烈競爭,OS 互斥量,線程阻塞
  4. 鎖消除:JIT 編譯器發現無共享數據競爭,直接消除鎖
  5. 鎖粗化:連續對同一對象加鎖解鎖,合併為一次大範圍鎖

最佳實踐原則

  • 縮小同步範圍:只同步必要代碼,非同步代碼移出塊外
  • 避免在同步塊調用外部方法:不可控的執行時間增加持鎖時長
  • 優先使用細粒度鎖:不同資源不同鎖,但注意死鎖 (固定獲取順序)
  • 考慮 Lock 接口:需要可中斷、超時、公平鎖、條件變量時使用 ReentrantLock
  • 不可變對象天然線程安全:無狀態、final 域、安全發布

常見誤區

  1. synchronized 修飾方法等價於 synchronized(this) { 方法體 },但字節碼標識不同 (ACC_SYNCHRONIZED vs monitorenter/monitorexit)
  2. 構造函數不能加 synchronized (對象未構造完成,多線程不可見)
  3. String 常量池導致的意外共享鎖:synchronized("lock") 可能鎖住全局同一字符串
  4. 鎖對象為 null 會拋 NPE

深入理解 synchronized 的四種用法、鎖對象本質及 JVM 優化機制,是寫出高性能、無死鎖併發代碼的關鍵。

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