在並發編程領域,開發者往往將焦點集中在鎖、同步器等代碼層面的共享變量訪問控制上,卻鮮少關注 CPU 緩存架構、JVM 底層機制等硬體因素對性能的深遠影響。早期學習高性能異步框架 Disruptor 時,發現其被譽為「最快消息框架」,單線程每秒可處理 600 萬訂單,其核心優勢之一便在於巧妙規避了偽共享。業界常將緩存行上的寫競爭視為 SMP 系統中並行線程擴展性的首要瓶頸,而偽共享因代碼難以直觀察覺,故被喻為「無聲的性能殺手」。
非正式定義:緩存系統以緩存行為單位存儲數據。當多線程修改互不相干的變量,卻因這些變量共享同一緩存行,導致彼此性能受損,此現象即為偽共享。
CPU 與主內存速度差距巨大,緩存應運而生。現代 CPU 擁有多級緩存:L1、L2 獨享於各核心,L3 則由同插槽核心共享。數據讀取順序為 L1 → L2 → L3 → 主存,越靠近 CPU 越快越小。三級緩存命中率可達 95% 以上。
多核環境下,核心間緩存一致性靠 MESI 協議維護,緩存行有四種狀態:
當核心需修改共享狀態(S)的緩存行時,會發出 RFO (Request For Ownership) 請求,使其他核對應緩存行失效(I),獨佔該行。此過程涉及總線鎖定、狀態廣播,開銷極大。
典型緩存行大小 64 字節。Java long 佔 8 字節,一行可容納 8 個。若多線程操作數組中相鄰的 long 變量,實則共享同一緩存行,引發偽共享。
public final static class VolatileLong {
public volatile long value = 0L;
public long p1, p2, p3, p4, p5, p6; // 填充 6 個 long (48 字節) + 對象頭 8/12 字節 ≈ 64 字節
}
實驗證明:無填充時 4 線程並發寫入耗時約為填充後的 2.5 倍。隨線程數增加,偽共享頻率升高,性能惡化顯著。
@Contended 註解自動填充。__declspec(align(64)) 強制變量按緩存行對齊;Java 需靠填充實現。LinkedBlockingQueue 的 head/tail 易共享緩存行。雖偽共享隱蔽且危害大,但並非所有系統都需極力消除:
結論:僅在高併發熱點路徑、極致低延遲場景(如 Disruptor、金融交易系統)才值得投入精力解決偽共享。