HashMap 與 HashTable的對比

HashMap為何數(shù)組的長度是2的n次方

  • 1.這個方法非常巧妙, 它通過 h & (table.length -1) 來得到該對象的保存位, 而HashMap 底層數(shù)組的長度總是 2 的 n 次方, 2n-1 得到的二進制數(shù)的每個位上的值都為 1,那么與全部為 1 的一個數(shù)進行與操作, 速度會大大提升。

  • 2.當 length 總是 2 的 n 次方時, h& (length-1)運算等價于對 length 取模, 也就是h%length, 但是&比%具有更高的效率

  • 3.當數(shù)組長度為 2 的 n 次冪的時候, 不同的 key 算得的 index 相同的幾率較小,那么數(shù)據(jù)在數(shù)組上分布就比較均勻, 也就是說碰撞的幾率小, 相對的, 查詢的時候不用遍歷某個位置上的鏈表, 這樣查詢效率也就較高了。

HashMap 的擴容機制:

而負載因子表示一個散列表的空間的使用程度,有這樣一個公式:initailCapacity*loadFactor=HashMap的容量。

所以負載因子越大則散列表的裝填程度越高,也就是能容納更多的元素,元素多了,鏈表大了,所以此時索引效率就會降低。

反之,負載因子越小則鏈表中的數(shù)據(jù)量就越稀疏,此時會對空間造成爛費,但是此時索引效率高。

當 HashMap 中的結(jié)點個數(shù)超過數(shù)組大小loadFactor(加載因子) 時, 就會進數(shù)組擴容,loadFactor 的默認值為 0.75。也就是說,默認情況下,數(shù)組大小為 16,那么當 HashMap中結(jié)點個數(shù)超過 160.75=12 的時候, 就把數(shù)組的大小擴展為2*16=32, 即擴大一倍, 然后重新計算每個元素在數(shù)組中的位置, 并放進去, 而這是一個非常消耗性能的操作。

多線程下 HashMap 出現(xiàn)的問題:

  • 1.多線程 put 操作后, get 操作導(dǎo)致死循環(huán),導(dǎo)致 cpu100%的現(xiàn)象。 主要是多線程同時put 時, 如果同時觸發(fā)了 rehash 操作, 會導(dǎo)致擴容后的 HashMap 中的鏈表中出現(xiàn)循環(huán)節(jié)點, 進而使得后面 get 的時候, 會死循環(huán)。

  • 2.多線程 put 操作, 導(dǎo)致元素丟失, 也是發(fā)生在多個線程對 hashmap 擴容時。

HashMap 和 HashTable 的區(qū)別

    1. Hashtable 是線程安全的, 方法是 Synchronized 的, 適合在多線程環(huán)境中使用, 效率稍低; HashMap 不是線程安全的, 方法不是 Synchronized 的, 效率稍高, 適合在單線程環(huán)境 下 使 用 , 所 以 在 多 線 程 場 合 下 使 用 的 話 , 需 要 手 動 同 步 HashMap ,Collections.synchronizedMap()。
  • 2.HashMap 的 key 和 value 都可以為 null 值, HashTable 的 key 和 value 都不允許有 Null 值。

  • 3.HashMap 中數(shù)組的默認大小是 16, 而且一定是 2 的倍數(shù), 擴容后的數(shù)組長度是之前數(shù)組長度的 2 倍。 HashTable 中數(shù)組默認大小是 11, 擴容后的數(shù)組長度是之前數(shù)組長度的 2 倍+1。

  • 4.哈希值的使用不同

  • 5 HashMap 重新計算 hash 值, 而且用&代替求模

HashTable 的效率比較低的原因

在線程競爭激烈的情況下 HashTable 的效率非常低下。 因為當一個線程訪問HashTable 的同步方法時, 訪問其他同步方法的線程就可能會進入阻塞或者輪訓(xùn)狀態(tài)。 如線程 1 使用 put 進行添加元素, 線程 2 不但不能使用 put 方法添加元素, 并且也不能使用get 方法來獲取元素, 所以競爭越激烈效率越低

判斷是否含有某個鍵

在 HashMap 中, null 可以作為鍵, 這樣的鍵只有一個; 可以有一個或多個鍵所對應(yīng)的值為 null。 當 get()方法返回 null 值時, 既可以表示 HashMap 中沒有該鍵, 也可以表示該鍵所對應(yīng)的值為 null。 因此, 在 HashMap 中不能用 get()方法來判斷 HashMap 中是否存在某個鍵, 而應(yīng)該用 containsKey()方法來判斷。 Hashtable 的鍵值都不能為 null, 所以可以用 get()方法來判斷是否含有某個鍵。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容