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

Java 多執行緒核心:synchronized 關鍵字深度解析(物件鎖、方法鎖、同步塊、記憶體可見性)

     編輯:Java 相關知識

一、synchronized 三種鎖定方式

1. 修飾實例方法 → 鎖當前物件

public class MyObject {
    public synchronized void methodA() {
        // 鎖定 this
    }
}

等同於:

public void methodA() {
    synchronized(this) { /* ... */ }
}

2. 修飾靜態方法 → 鎖 Class 物件

public class MyObject {
    public static synchronized void staticMethod() {
        // 鎖定 MyObject.class
    }
}

3. 同步代碼塊 → 鎖指定物件

public void methodB() {
    synchronized(lockObject) { // 可鎖 this、自定義物件、Class 物件
        // 臨界區
    }
}

二、核心特性:同步互斥與記憶體可見性

1. 互斥性

同一把鎖同一時間只能被一個執行緒持有。同一物件的多個 synchronized 方法互斥:

public class Counter {
    private int count = 0;
    public synchronized void increment() { count++; }
    public synchronized void decrement() { count--; }
    public synchronized int get() { return count; }
}

執行緒 A 呼叫 increment() 時,執行緒 B 呼叫 decrement() 或 get() 會阻塞等待。

2. 可見性

synchronized 語義包含 解鎖前將工作記憶體刷新到主記憶體、加鎖後從主記憶體讀取最新值,保證多執行緒對共享變數修改的可見性(JMM happens-before 規則)。

三、實戰案例:防止髒讀

public class UserAccount {
    private String username = "default";
    private String password = "default";

    public synchronized void update(String username, String password) {
        this.username = username;
        try { Thread.sleep(5000); } catch (InterruptedException e) {}
        this.password = password;
    }

    public synchronized void print() {
        System.out.println("user=" + username + ", pwd=" + password);
    }
}

場景模擬

  1. 執行緒 A 呼叫 update("newUser", "newPass"),執行到 sleep 釋放 CPU
  2. 若 print() 無 synchronized → 執行緒 B 讀到 username="newUser", password="default"(髒讀)
  3. 有 synchronized → 執行緒 B 阻塞等待 A 釋放鎖,讀到一致狀態

四、進階:鎖升級與偏向鎖 (JDK 6+)

鎖狀態適用場景特點
無鎖無競爭無開銷
偏向鎖單一執行緒重複進入CAS 設定 ThreadId,後續進入無同步開銷
輕量級鎖低競爭、短暫持有CAS 操作 Mark Word,自旋等待
重量級鎖高競爭、長時間持有OS 互斥量,執行緒阻塞/喚醒

五、最佳實踐與避坑

  • 鎖粒度最小化:同步塊優於同步方法,僅包裹臨界區
  • 避免鎖活物件:synchronized(new Object()) 每次新物件無效;用 final Object lock = new Object()
  • 不可變物件當鎖風險:String、Integer 常量池可能導致非預期共享鎖
  • 死鎖預防:固定鎖獲取順序、使用 tryLock(timeout)、避免巢狀鎖
  • 效能替代:ReentrantLock(可中斷、公平鎖、Condition)、Atomic*、LongAdder、ConcurrentHashMap

六、總結

synchronized 是 Java 並發基石,提供互斥與可見性雙重保證。理解鎖對象(this、Class、自定義)、鎖升級機制、JMM 語義,是寫出正確高效並發程式的前提。

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