並發編程是 Java 開發者最核心也最難掌握的技能之一,要求對計算機底層運行原理有深入理解。本文作為系列首篇,建立共享性、互斥性、原子性、可見性、有序性五大理論基石,後續文章將以此為基礎剖析 JUC 組件。
若所有數據僅在線程內有效,不存在線程安全問題。但多線程環境下數據共享不可避免(如數據庫數據)。
public class ShareData {
public static int count = 0;
public void addCount() { count++; } // 非原子操作
// 10線程各執行100次,預期1000,實際遠小於1000
}
運行結果呈現數據競爭導致計數丟失。
資源互斥指同一時間僅允許一個訪問者訪問。讀操作可共享,寫操作需互斥。Java 提供 synchronized、Lock 實現互斥。
public synchronized void addCount() { count++; } // 保證互斥,結果恆為1000
原子性指操作是獨立、不可分割的整體。i++ 實際分三步:讀取、加一、寫回,多線程下易產生競態條件。
synchronized、ReentrantLockJVM 內存模型:每個線程有工作內存 (對應 CPU 高速緩存),共享變量讀寫操作工作內存副本,稍後同步回主內存。導致線程 A 修改後,線程 B 可能讀不到最新值。
private static boolean ready = false; private static int number = 0; // Writer: number=100; ready=true; // Reader: if(!ready) print(ready); print(number); // 可能輸出 false 和 0 (可見性失效) 或 0 和 100 (重排序)
volatile:強制讀寫主內存,禁止指令重排序。synchronized:解鎖前將工作內存刷新回主內存。為提升效能,編譯器/處理器/內存系統可能重排序指令:
// 初始 x=y=0 // 線程1: x=1; r1=y; // 線程2: y=1; r2=x; // 可能結果: r1=0, r2=0 (發生重排序)
volatile:禁止重排序 (內存屏障)。synchronized:鎖內代碼對外有序 (鎖語義)。五大基石相互關聯:共享性引發問題,互斥性解決寫寫衝突,原子性保證操作完整,可見性保證讀寫同步,有序性防止重排序破壞邏輯。掌握這些理論,才能深入理解 JUC 組件設計原理。