2016-08-04 73 views
1

我們有一個應用程序,它使用了一個java.util.HashMap的實例,它通過各種間接方式共享,以便多個線程同時訪問它。我們現在解決了這個問題,因爲我們知道java.util.HashMap不是線程安全的,因此不應該同時訪問。HashMap掛起併發訪問

是固定的,我們發現了原因之前,我們有JDK(以IBM JDK 7 SR3)和之後的升級是升級,我們過程中HashMap實例的get操作經驗豐富的偶爾掛起(掛起發生在getEntry()方法中。)

出於好奇,我想知道,HashMap內部會發生什麼,導致掛起。影響併發訪問行爲的實現有什麼不同?

關於HashMap的實現,看起來,IBM JDK與Oracle JDK和OpenJDK相同,它與Java8版本(使用Node數據結構)又是不同的。

我認爲,difference between java7u40 b43 vs b147代表升級引入的更改。

我目前的假設是,對於杭原因與在addEntry方法的變化,從變化附加先調整,後調整大小先加載後

但是沒有人有確切的理解,在併發訪問期間究竟發生了什麼?

+0

數據競賽的定義是不可預測和隨意的。對JDK的改變可能是一個完全無關的輕微改變,導致一些進程需要更長的時間,令問題更加惡化。這個問題很可能是一直存在的問題,但從幾百萬分之一到幾千分之一。如果不重新創建問題並進行線程轉儲,幾乎肯定不可能確定原因。線程安全性不能通過測試來證明,而只能通過仔細分析代碼。 –

+0

「HashMap」中沒有'getEntry()'和'addEntry()'方法。你確定它在那裏,你掛了? –

+0

@OlivierGrégoire有內部。 –

回答

0

我最終調試了我們編寫的單元測試,並在線程掛起/循環時檢查HashMap的桶。事實上,當兩個線程同時調整地圖大小時,它們會在存儲桶中創建一個循環。它結束了這樣的結構:

bucket1[0].entry1.next = entry2; 
bucket1[0].entry2.next = entry1; 

更詳細的解釋在這裏可以Resizing the HashMap: dangers ahead

1

發現當調用一個hashmap.put(鍵,值),HashMap的閾值進行檢查。如果地圖大小超過此閾值,地圖將被重新調整大小,並且所有條目將被重新整理。
在多線程環境中,這會使您的HashMap處於不一致的狀態。至少應該保護應用程序中使用同步或鎖定寫入HashMap的調用。
我推薦使用java.util.concurrent.ConcurrentHashMap。