HashMap在1.7 1.8中的線程安全問題


HashMap的線程不安全主要體現在下面兩個方面:

在JDK1.7中,當並發執行擴容操作時會造成環形鏈和數據丟失的情況。
在JDK1.8中,在並發執行put操作時會發生數據覆蓋的情況。

 
 

常被問到的HashMap和Hashtable的區別

1、線程安全
兩者最主要的區別在於Hashtable是線程安全,而HashMap則非線程安全。
Hashtable的實現方法里面都添加了synchronized關鍵字來確保線程同步,因此相對而言HashMap性能會高一些,我們平時使用時若無特殊需求建議使用HashMap,在多線程環境下若使用HashMap需要使用Collections.synchronizedMap()方法來獲取一個線程安全的集合。

Note:Collections.synchronizedMap()實現原理是Collections定義了一個SynchronizedMap的內部類,這個類實現了Map接口,在調用方法時使用synchronized來保證線程同步,當然了實際上操作的還是我們傳入的HashMap實例,簡單的說就是Collections.synchronizedMap()方法幫我們在操作HashMap時自動添加了synchronized來實現線程同步,類似的其它Collections.synchronizedXX方法也是類似原理。

2、針對null的不同
HashMap可以使用null作為key,而Hashtable則不允許null作為key
雖說HashMap支持null值作為key,不過建議還是盡量避免這樣使用,因為一旦不小心使用了,若因此引發一些問題,排查起來很是費事。
Note:HashMap以null作為key時,總是存儲在table數組的第一個節點上。

3、繼承結構
HashMap是對Map接口的實現,HashTable實現了Map接口和Dictionary抽象類。

4、初始容量與擴容
HashMap的初始容量為16,Hashtable初始容量為11,兩者的填充因子默認都是0.75。

HashMap擴容時是當前容量翻倍即:capacity2,Hashtable擴容時是容量翻倍+1即:capacity2+1。

5、兩者計算hash的方法不同
Hashtable計算hash是直接使用key的hashcode對table數組的長度直接進行取模

int hash = key.hashCode();
int index = (hash & 0x7FFFFFFF) % tab.length;

 
 

怎么解決這個線程不安全的問題

  • Java中有HashTable、Collections.synchronizedMap、以及ConcurrentHashMap可以實現線程安全的Map。

  • HashTable是直接在操作方法上加synchronized關鍵字,鎖住整個數組,粒度比較大,

  • Collections.synchronizedMap是使用Collections集合工具的內部類,通過傳入Map封裝出一個SynchronizedMap對象,內部定義了一個對象鎖,方法內通過對象鎖實現

  • ConcurrentHashMap使用分段鎖,降低了鎖粒度,讓並發度大大提高。
     
     

為啥Hashtable 是不允許鍵或值為 null 的,HashMap 的鍵值則都可以為 null?

因為hashtable,concurrenthashmap它們是用於多線程的,並發的 ,如果map.get(key)得到了null,不能判斷到底是映射的value是null,還是因為沒有找到對應的key而為空

翻譯一下最后一句話,其實contains(key)也是可以使用synchronized進行同步的,所以調用contains(key)得到的就是該線程本時刻map的狀態,本身不存在歧義。問題的關鍵在於多線程情況下,即便此刻你通過contains(key)知曉了是否包含null,下一步當你使用這個結果去做一些事情時可能其他線程已經改變了這種狀態,這在單線程下是不可能發生的。

這是因為Hashtable使用的是安全失敗機制(fail-safe),這種機制會使你此次讀到的數據不一定是最新的數據。
如果你使用null值,就會使得其無法判斷對應的key是不存在還是為空,因為你無法再調用一次contain(key)來對key是否存在進行判斷(意思是contains不可靠,看上面那一段),ConcurrentHashMap同理。

資料


免責聲明!

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



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