不一樣的內容:死磕JDK8中ConcurrentHashMap.computeIfAbsent 死循環 Bug


背景:

   最近有朋友提到了JDK1.8中的ConcurrentHashMap有可能引起CPU飆升的問題,立馬惡補,因為運行的生產環境就是1.8版本的,希望沒有采坑。

瀏覽后,發現網上文章千篇一律,不全面。經過一上午的分析、研究,總結如下,共同進步~~~~~~~~~~~~

之前文章中提到過《JDK1.7中HashMap引起CPU100%的問題》,那么JDK8中的ConcurrentHashMap也不一定是安全的。
官方Bug報告: https://bugs.openjdk.java.net/browse/JDK-8062841
JDK9中變化內容: http://hg.openjdk.java.net/jdk9/jdk9/jdk/rev/6dd59c01f011

再次描述下這個bug,運行如下程序

Map<String, Integer> map = new ConcurrentHashMap<>();
map.computeIfAbsent("a", key -> {
    map.put("a", 2);
    return 1;
});

 

JDK1.8中 computeIfAbsent 部分代碼

 

 

ReservationNode 在 computeIfAbsent() 方法構建 value 值的時候被用作占位節點。換句話說,computeIfAbsent() 方法會初始化一個 ReservationNode 來占位,它會等待計算完畢后替換當前的占位對象。此時,如果正好趕在 ConcurrentHashMap 達到容量 0.75 的時候進行擴容,由於ConcurrentHashMap 擴容忽略了 ReservationNode 情況。調用put的時候在synchronized (f)沒有對ReservationNode處理,所以會出現死循環。因此,可能會導致擴容無法替換占位符,同時占位符等待替換的情況,然后就一直 for 循環處理了。

這也是為什么網上很多人說,如果不存在遞歸調用computeIfAbsent()是不會發生的。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM