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

Java synchronized 關鍵字深度解析:鎖機制、同步方法與同步塊完整指南

     編輯:J2ME

前言

synchronized 是 Java 多執行緒同步的核心關鍵字,雖然使用看似簡單,但其底層鎖機制、作用範圍與潛在陷阱卻常被忽視。本文將從鎖的本質、不同使用場景的行為差異、最佳實踐等方面進行深度剖析。

核心概念:鎖的是對象,不是代碼

無論 synchronized 修飾方法還是代碼塊,它獲取的鎖始終是對象,而非某段代碼或方法。每個對象只有一把鎖。理解這一點是避免同步失效的關鍵。

三種主要使用形式

1. 同步實例方法

public synchronized void methodAAA() {
    // 同步代碼
}

等價於:

public void methodAAA() {
    synchronized (this) {
        // 同步代碼
    }
}

鎖對象:調用該方法的實例對象(如 P1)。

行為:同一對象的不同執行緒間互斥;但不同對象(如 P2)可同時調用該方法,互不干擾。若共享數據屬於類層級(static),此方式無法保護。

2. 同步代碼塊

public void method3(SomeObject so) {
    synchronized (so) {
        // 同步代碼
    }
}

鎖對象:括號內指定的對象 so。誰持有這把鎖,誰就能執行塊內代碼。

技巧:無明確鎖對象時,可創建專用 private byte[] lock = new byte[0]; 作為鎖。零長度 byte 陣列比 new Object() 更輕量(字節碼指令更少)。

3. 同步靜態方法 / Class Literal 鎖

class Foo {
    public synchronized static void staticMethod() { ... }
    
    public void instanceMethod() {
        synchronized (Foo.class) { ... } // 等價於上方
    }
}

鎖對象:當前類的 Class 對象(Foo.class)。

關鍵差異:靜態同步方法鎖住 Class 對象,實例同步方法鎖住實例對象(this)。兩者鎖不同,互不阻塞。同一對象同時訪問靜態同步方法與實例同步方法不會同步。

常見誤區與最佳實踐

誤區:使用 P1.getClass() 鎖定類

P1.getClass() 可能返回子類的 Class 對象,而非 Foo.class,導致鎖不一致。請直接使用 Foo.class。

封裝性與線程安全

  1. 私有化實例變量 + 同步 getter:防止外部繞過同步直接修改。
  2. 可變對象(如集合)需防御性複製:getter 回傳 clone() 或不可變視圖,避免內部狀態被外部竄改。
  3. 同步 getter:確保讀取過程也受鎖保護。
private List list = new ArrayList<>();

public synchronized List getList() {
    return new ArrayList<>(list); // 返回副本
}

效能與死鎖警示

  • 同步有顯著系統開銷,盡量縮小同步範圍。
  • 不當的鎖順序易導致死鎖,設計時需建立全局鎖獲取順序規範。
  • JDK 5+ 提供 java.util.concurrent.locks.ReentrantLock 等更靈活的鎖實現,複雜場景優先考慮。

總結

搞清楚 synchronized 鎖定的是哪個對象,是編寫正確多執行緒程式的基石。實例方法鎖 this,靜態方法鎖 Class 對象,同步塊鎖指定對象。封裝共享狀態、縮小同步粒度、避免死鎖,是實戰核心原則。

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