比較 | HashMap | HashTable |
存儲結構 |
數組 + 鏈表/紅黑樹 | 數組 + 鏈表 |
擴容方式 |
oldCap * 2 | oldCap * 2 + 1 |
K,V能否爲null | key, value 均可以爲 null | key, value 均不可以爲 null |
線程是否安全 |
線程不安全 | 線程安全 |
HashMap的存儲規則:
優先使用數組存儲, 如果出現Hash衝突, 將在數組的該位置拉伸出鏈表進行存儲(在鏈表的尾部進行添加), 如果鏈表的長度大於設定值後, 將鏈表轉爲紅黑樹。
擴容方式:
Hashtable默認的初始大小爲11,之後每次擴充,容量變爲原來的2n+1。HashMap默認的初始化大小爲16。之後每次擴充,容量變爲原來的2倍。
創建時,如果給定了容量初始值,那麼Hashtable會直接使用你給定的大小,而HashMap會將其擴充爲2的冪次方大小。也就是說Hashtable會盡量使用素數、奇數。而HashMap則總是使用2的冪作爲哈希表的大小。
之所以會有這樣的不同,是因爲Hashtable和HashMap設計時的側重點不同。Hashtable的側重點是哈希的結果更加均勻,使得哈希衝突減少。當哈希表的大小爲素數時,簡單的取模哈希的結果會更加均勻。而HashMap則更加關注hash的計算效率問題。在取模計算時,如果模數是2的冪,那麼我們可以直接使用位運算來得到結果,效率要大大高於做除法。HashMap爲了加快hash的速度,將哈希表的大小固定爲了2的冪。當然這引入了哈希分佈不均勻的問題,所以HashMap爲解決這問題,又對hash算法做了一些改動。這從而導致了Hashtable和HashMap的計算hash值的方法不同
關於線程安全問題:
Hashtable是線程安全的,它的每個方法中都加入了Synchronize方法。在多線程併發的環境下,可以直接使用Hashtable,不需要自己爲它的方法實現同步
HashMap不是線程安全的,在多線程併發的環境下,可能會產生死鎖等問題。使用HashMap時就必須要自己增加同步處理,
雖然HashMap不是線程安全的,但是它的效率會比Hashtable要好很多。這樣設計是合理的。在我們的日常使用當中,大部分時間是單線程操作的。HashMap把這部分操作解放出來了。當需要多線程操作的時候可以使用線程安全的ConcurrentHashMap。ConcurrentHashMap雖然也是線程安全的,但是它的效率比Hashtable要高好多倍。因爲ConcurrentHashMap使用了分段鎖,並不對整個數據進行鎖定。
另外:Hashtable 基本已經被棄用,在 Java 5 之後用 ConcurrentHashMap 來替代。
參考資料:https://blog.csdn.net/charmingwong/article/details/71503459