多線程環境下,共享資源(變量、文件、數據庫連接等)若無協調機制,會導致 數據競態條件,產生髒讀、丟失更新等嚴重問題。Java 提供 synchronized 關鍵字作為內建鎖機制,確保同一時刻僅有一個線程能訪問受保護的代碼區域。
理解這三條規則是掌握 synchronized 的鑰匙
| 規則 | 描述 | 關鍵點 |
|---|---|---|
| ① 同一對象的同步方法/塊互斥 | 線程 A 進入對象 obj 的同步區域時,線程 B 嘗試進入 obj 的同一同步區域將阻塞 | 鎖針對「對象實例」 |
| ② 同步不阻塞非同步代碼 | 線程 A 持有 obj 鎖時,線程 B 仍可自由訪問 obj 的非同步方法/塊 | 非同步區域無鎖保護 |
| ③ 同一對象的不同同步區域互斥 | 線程 A 在 obj 的同步方法 1,線程 B 嘗試進入 obj 的同步方法 2/塊 → 阻塞 | 同一對象只有一把鎖 |
// 同步實例方法
public synchronized void instanceMethod() { ... }
// 同步代碼塊(鎖當前實例)
public void blockSync() {
synchronized(this) { ... }
}
// 同步代碼塊(鎖指定實例)
public void customLock(Object lock) {
synchronized(lock) { ... }
}
特點:不同實例互不干擾,適合保護實例級共享狀態。
// 同步靜態方法
public static synchronized void staticMethod() { ... }
// 同步代碼塊(鎖 Class 對象)
public static void classBlockSync() {
synchronized(MyClass.class) { ... }
}
特點:全進程唯一,所有實例共享同一把鎖,適合保護類級共享狀態(如靜態變量、單例初始化)。
class SharedTask implements Runnable {
public void run() {
synchronized(this) { // 鎖住 SharedTask 實例
for (int i=0; i<5; i++) {
System.out.println(Thread.currentThread().getName() + " - " + i);
sleep(100);
}
}
}
}
public class Demo1 {
public static void main(String[] args) {
SharedTask task = new SharedTask(); // 單一實例
new Thread(task, "T1").start();
new Thread(task, "T2").start();
}
}
// 輸出:T1 連續打印 0-4,然後 T2 打印 0-4(串行)
class MyThread extends Thread {
public void run() {
synchronized(this) { // 鎖住各自的 Thread 實例(不同對象!)
for (int i=0; i<5; i++) { ... }
}
}
}
public class Demo2 {
public static void main(String[] args) {
new MyThread("T1").start();
new MyThread("T2").start();
}
}
// 輸出:T1、T2 交替打印(並行)
核心差異: `synchronized(this)` 中的 `this` 指向當前類的實例。案例 1 共享同一 Runnable 實例;案例 2 每個 Thread 都是獨立實例。
// 同步整個方法 - 粒度粗,簡單但可能降低並發度
public synchronized void coarseSync() { ... }
// 同步代碼塊 - 粒度細,僅鎖保護必要區域
public void fineSync() {
// 非同步預處理...
synchronized(this) {
// 核心臨界區
}
// 非同步後處理...
}
基準測試 顯示:細粒度同步塊通常比整個方法同步快 2-3 倍(視臨界區佔比而定)。
public class Singleton {
private static volatile Singleton instance; // volatile 禁止指令重排
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) { // 第一次檢查(無鎖,高性能)
synchronized (Singleton.class) { // 類鎖
if (instance == null) { // 第二次檢查(防重複創建)
instance = new Singleton();
}
}
}
return instance;
}
}
volatile 確保:寫入 instance 時,對象構造完成前不對其他線程可見synchronized 是 Java 並發編程的基石。深入理解其鎖機制、作用域規則與實例/類鎖區別,配合 volatile、DCL 等進階模式,能構建高效、線程安全的並發系統。實戰中應遵循「最小鎖範圍、明確鎖所有權」原則,必要時升級至 `java.util.concurrent` 套件。