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

Java synchronized 鎖機制深度解析:同一把鎖、對象鎖、類鎖與死鎖避坑

     編輯:Java 綜合教學

Java synchronized 鎖機制深度解析:同一把鎖、對象鎖、類鎖與死鎖避坑

synchronized 是 Java 並發編程的基石,保證臨界區的原子性與可見性。但「鎖住的是誰」往往是新手最易踩的坑。本文通過層層遞進的反面教材,徹底講清鎖對象、this、類對象的區別,並給出死鎖預防原則。

核心原則:同一把鎖,才能互斥

  • 多線程訪問同步代碼時,必須鎖定同一個對象實例(或同一個 Class 對象)。
  • 鎖對象不同 = 沒有互斥關係 = 線程不安全。

場景 1:錯誤示範 —— 鎖住方法參數

class OutPuter {
    public void outer(String name) {
        synchronized (name) {  // 危險!name 是參數,每次調用可能不同對象
            for (char c : name.toCharArray()) System.out.print(c);
            System.out.println();
        }
    }
}
// 線程 1 傳 "abcdefg",線程 2 傳 "123456789" → 兩把不同的鎖 → 交替輸出,線程不安全

場景 2:正確 —— 鎖住 this(實例對象)

class OutPuter {
    public void outer(String name) {
        synchronized (this) {  // 同一個 OutPuter 實例 → 同一把鎖
            for (char c : name.toCharArray()) System.out.print(c);
            System.out.println();
        }
    }
}
// 或直接在方法上加 synchronized(隱式鎖 this)
public synchronized void outer(String name) { ... }

場景 3:多方法共享同一把鎖

class OutPuter {
    public synchronized void outer(String name) { ... }   // 鎖 this
    public synchronized void outer2(String name) { ... }  // 也鎖 this
}
// 兩個方法互斥,因為鎖對象都是同一個 OutPuter 實例

場景 4:錯誤 —— new 出不同實例

// 線程 1
outPuter.outer("abcdefg");
// 線程 2 —— 重新 new 了一個對象!
new OutPuter().outer("123456789");  // 不同實例 → 不同鎖 → 線程不安全

場景 5:靜態方法與類鎖

class OutPuter {
    public static synchronized void outer3(String name) { ... } // 鎖 OutPuter.class
    public synchronized void outer(String name) { ... }         // 鎖 this
}
// 靜態鎖(類鎖)與實例鎖(對象鎖)完全無關 → 不互斥

修正:實例方法改鎖類對象

public void outer(String name) {
    synchronized (OutPuter.class) { ... } // 現在與 outer3 共享類鎖
}

鎖對象對照表

同步方式鎖對象作用範圍
synchronized(instanceMethod)當前實例 this同一實例的所有實例同步方法互斥
synchronized(this)當前實例 this同上
synchronized(lockObj)自定義 Lock 對象共享該 lockObj 的代碼塊互斥
static synchronized method當前類 Class 對象所有實例的該靜態方法互斥
synchronized(MyClass.class)指定類 Class 對象跨實例、跨方法的類級別互斥

死鎖預防三條鐵律

  1. 固定加鎖順序:多把鎖時,全局統一獲取順序(如按 hashCode 排序)。
  2. 避免長時間持有鎖:同步塊內只放核心邏輯,I/O、睡眠、複雜計算移出。
  3. 優先用並發包工具:ReentrantLock 支持 tryLock(timeout) 可中斷,CountDownLatch/Semaphore 替代 wait/notify。

最佳實踐清單

  • ✅ 實例方法同步首選 synchronized(this) 或方法級 synchronized。
  • ✅ 靜態變量/類級資源用 synchronized(ClassName.class)。
  • ✅ 共享可變對象作為鎖時,確保該對象不可變且單例(如 private final Object lock = new Object();)。
  • ❌ 絕不鎖 String、Integer、方法參數等可能被池化或替換的對象。
  • ❌ 避免在同步塊內調用外部方法(可能導致死鎖或長時間持鎖)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved