開發者常編寫微基準來比較同步機制性能,但 Java 動態編譯(JIT)特性極易導致測試結果失真。本文以一個對比 synchronized 與 ReentrantLock 的 SyncLockTest 為例,深度剖析其在構想、方法、實現三個層面的缺陷,並闡述如何編寫可信的效能測試。
基準測試僅單線程執行,完全缺乏鎖競爭。實際生產環境中,同步性能瓶頸多發生於高競爭、多處理器場景。無競爭同步經過 JVM 優化(偏向鎖、輕量級鎖)已極快,而有競爭時涉及線程阻塞/喚醒、系統調用,性能差異巨大。測試必須模擬真實競爭程度。
僅在單核筆記本、單一 JDK 版本上運行,忽略了處理器架構(x86 vs SPARC)、核心數、內存模型對並發原語(CAS、內存屏障)性能的決定性影響。可靠結論需跨平台、多配置驗證。
test(SyncIncrementer) 時 JIT 內聯虛方法;二次調用 test(LockIncrementer) 觸發類加載導致去優化,雙方執行路徑不對等。synchronized 塊為空易被整個刪除;ReentrantLock 呼叫鏈較複雜可能殘留。編譯器對兩種鎖的優化力度不同,且此優化在真實業務代碼中不會發生。synchronized 相鄰塊可合併,甚至將整個循環縮減為單次遞增;ReentrantLock 無此優化。微基準試圖隔離單一操作,但「無填充」會被編譯器優化掉,「過度填充」又掩蓋真實開銷。JIT 根據運行時概要優化,測試代碼與生產代碼的優化結果往往背道而馳。
「微基準總會產生一個數字,即使這個數字毫無意義。」—— 編寫良好的微基準需要深厚的 JVM、JIT、處理器架構知識,否則不如直接測試真實系統。