今天在生產環境遇到一個問題,Java 應用程序的 cpu 使用比例很高,導致整台機器的 cpu 使用率高達 90% ,正常情況下是 20% 左右。
把 Thread dump 導出來,利用 IBM Thread Analyzer for Java 工具進行分析。總共有60 多個在線線程,其中有 15 個線程都在執行同一個文件中的同一句代碼,最頂層的調用是 HashMap.get() 。
HashMap 的底層數據結構是數組 + 鏈表進行存儲,鏈表用於處理 hash 碰撞的情況。正常情況下鏈接是線性鏈表,當數據結構在並發情況下被污染了,導致出現環形鏈表,則會出現程序的無限循環。
15 個線程在同一時間都在執行同一行代碼,是很不正常的情況。當線程調用 HashMap.get 並在鏈表上搜索時,碰巧遇到的是被污染的環形鏈接,就能解釋得通這個異常情況了。
HashMap 是非線程安全,在多線程並發訪問時,有可能出現環形鏈表。詳細且清晰的分析,參考:
Explain the timing causing HashMap.put() to execute an infinite loop
附:關於 HashMap 源碼閱讀筆記