JVM 中存在主內存,每個線程有私有的工作內存。線程操作變量時:
多線程同時操作同一變量,若無同步機制,會導致臟讀、丟失更新、指令重排等不可預知結果。線程安全的目標:保證原子性、可見性、有序性。
// 同步代碼塊(推薦,粒度細)
synchronized(lockObject) {
// 臨界區
}
// 同步方法(鎖住整個對象 this)
public synchronized void method() { ... }
// 靜態同步方法(鎖住 Class 對象)
public static synchronized void staticMethod() { ... }
三個操作數:
當且僅當 V == A 時,原子性將 V 更新為 B,否則不動作並返回失敗。現代 CPU 提供指令級支持(如 x86 CMPXCHG),Java 通過 Unsafe.compareAndSwapInt 本地方法調用。
private volatile int value; // volatile 保證可見性
public final int get() {
return value;
}
public final int incrementAndGet() {
for (;;) { // 自旋
int current = get();
int next = current + 1;
if (compareAndSet(current, next))
return next;
}
}
volatile:禁止指令重排,強制從主內存讀寫,保證可見性| 場景 | 推薦方案 | 理由 |
|---|---|---|
| 高競爭、複雜邏輯 | synchronized / ReentrantLock | 避免自旋浪費 CPU,支持條件變量 |
| 低競爭、單變量操作 | AtomicInteger / LongAdder | 無鎖、吞吐高 |
| 計數器、統計 | LongAdder (Java 8+) | 分段累加,高併發下優於 AtomicLong |
| 復雜條件同步 | ReentrantLock + Condition | 支持公平鎖、可中斷、多條件 |
volatile 僅保證單次讀寫的原子性與可見性,不保證複合操作原子性(如 i++、check-then-act)。複合操作需配合鎖或原子類。
理解 JMM、內置鎖優化演進、CAS 硬件語義與原子類實現,是寫出高併發正確代碼的基石。實際開發中:優先用高級併發工具,必要時才手寫同步。