Android/Java 開發中常見疑問:多線程同時調用同一個類的 static 靜態方法,會發生什麼?是否線程安全?本文從內存模型、鎖機制、代碼實戰三個維度徹底講透。
| 場景 | 線程安全? | 原因 |
|---|---|---|
| 靜態方法僅使用局部變量/參數 | ✅ 安全 | 每線程獨擁棧幀,局部變量隔離 |
| 靜態方法讀寫靜態字段 | ❌ 不安全 | 所有線程共享堆中唯一靜態字段 |
靜態方法 + synchronized | ✅ 安全 | 鎖住 Class 對象,互斥執行 |
實例方法 + synchronized | ✅ 安全(同實例) | 鎖住 this 實例,不同實例互不影響 |
public class StaticDemo {
private static int staticField = 0; // 方法區/堆:全線程共享
private int instanceField = 0; // 堆:每實例一份
public static void staticMethod() {
int localVar = 0; // 棟幀:線程私有
staticField++; // 競態條件!
localVar++; // 線程安全
}
}
public class SyncStatic {
// 靜態同步方法
public static synchronized void staticSync() {
// 鎖對象:SyncStatic.class (Class 對象)
}
// 等價同步塊寫法
public static void staticSyncBlock() {
synchronized (SyncStatic.class) { // 顯式指定 Class 鎖
// ...
}
}
}
staticSyncA(),線程 B 必須等待才能進入 staticSyncB()this,靜態方法鎖 Class
public class UnsafeCounter {
private static int count = 0;
public static void increment() { count++; } // 非原子操作:讀-改-寫
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> { for(int i=0;i<100000;i++) increment(); });
Thread t2 = new Thread(() -> { for(int i=0;i<100000;i++) increment(); });
t1.start(); t2.start(); t1.join(); t2.join();
System.out.println(count); // 輸出 < 200000,如 134567
}
}
public static synchronized void incrementSync() { count++; }
// 或
public static void incrementBlock() { synchronized(UnsafeCounter.class) { count++; } }
// 輸出穩定 200000
public class ThreadLocalDemo {
private static ThreadLocal threadLocalCount = ThreadLocal.withInitial(() -> 0);
public static void increment() {
threadLocalCount.set(threadLocalCount.get() + 1);
}
// 每線程獨立計數,無競爭,但無法匯總全局值
}
| 維度 | 實例同步方法 | 靜態同步方法 |
|---|---|---|
| 鎖對象 | 當前實例 this | 當前類 Class 對象 |
| 作用範圍 | 同一實例的所有同步方法互斥 | 所有實例共享,類級別互斥 |
| 不同實例 | 可並發執行 | 仍互斥 (同一把 Class 鎖) |
| 字節碼標誌 | ACC_SYNCHRONIZED | ACC_SYNCHRONIZED |
| 等價同步塊 | synchronized(this) | synchronized(Clazz.class) |
AtomicInteger、ConcurrentHashMap、LongAdder 替代手工同步理解「靜態方法鎖 Class 對象」是 Java 並發編程的分水嶺。很多看似離奇的線程安全問題,本質上都是共享可變狀態在作祟。掌握內存模型、鎖機制、無鎖替代方案,才能寫出經得起高併發考驗的代碼。