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

Java 線程安全核心:synchronized 關鍵字深度解析與實戰陷阱

     編輯:Java 綜合教學

Java 同步機制權威指南:從原理到避坑的 synchronized 完全手冊

並發編程核心矛盾:效率與一致性的博弈。共享可變狀態是線程安全問題根源,synchronized 提供互斥訪問保證。

線程安全問題本質

非原子操作 m++ 拆解為:讀取 → 修改 → 寫入。多線程交替執行導致更新丟失:

private static volatile int m = 0;
// 兩線程各執行 10000 次 m++,預期 20000,實際 < 20000

synchronized 兩大使用形態

1. 同步代碼塊(精細控制鎖範圍)

// 鎖對象實例
synchronized (this) { m++; }

// 鎖自定義對象(推薦:封裝性更好)
private final Object lock = new Object();
synchronized (lock) { m++; }

2. 同步方法(隱式鎖當前實例/類對象)

// 實例方法:鎖 this
public synchronized void run() { m++; }

// 靜態方法:鎖 Class 對象
public static synchronized void count() { m++; }

致命陷阱:鎖對象不一致導致同步失效

錯誤示例:每次 new Runnable 創建線程,導致同步方法鎖住不同實例:

// 錯誤:兩個線程持有不同鎖
new Thread(new SynchronizedTest()).start();
new Thread(new SynchronizedTest()).start();

// 正確:共享同一 Runnable 實例
Runnable task = new SynchronizedTest();
new Thread(task).start();
new Thread(task).start();

靜態同步方法的類級鎖特性

將核心邏輯提取為 static synchronized 方法,鎖住 SynchronizedTest.class,JVM 僅加載一次 Class 對象,天然全局唯一:

public void run() { for(...) count(); }
public static synchronized void count() { m++; }

監視器對象模型

  • 每個 Java 對象關聯一個 Monitor(監視器/鎖標記)
  • 線程進入同步區需獲取 Monitor,退出時釋放
  • JVM 內部通過 monitorenter/monitorexit 字節碼指令實現

最佳實踐總結

  1. 鎖粒度最小化:同步塊優於同步方法,僅包裹臨界區
  2. 鎖對象不可變:用 final Object lock = new Object(),避免鎖對象被替換
  3. 避免鎖字符串常量:字符串常量池可能導致非預期共享鎖
  4. 靜態/實例鎖分離:靜態方法鎖 Class,實例方法鎖 this,互不干擾
  5. 考慮 ReentrantLock:需可中斷、公平鎖、條件變量時優先選擇

synchronized 是 JVM 內建的重量級鎖(JDK 1.6+ 引入偏向鎖、輕量級鎖優化),理解其語義與陷阱,是寫正確並發代碼的基石。

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