hashMap歸納


Hashmap的與hashtable的區別:

Hashmap:允許key為空;查詢速度快(他是非同步的:避免了同步中不必要的判斷);不安全的(容易引  發多線程安全問題)

Hashtable:不允許key為空,查詢速度慢(他是線程同步的,從而降低了效率,但是保證了安全)

Hashmap已經取代hashtable

你知道hashmap的工作原理嗎?

HashMap是基於hashing的原理,我們使用put(key, value)存儲對象到HashMap中,使用get(key)從HashMap 中獲取對象。當我們給put()方法傳遞鍵和值時,我們先對鍵調用 hashCode()方法,返回的hashCode用於 找到bucket位置來儲存Entry對象。”HashMap是在 bucket中儲存鍵對象和值對象,作為Map.Entry。

當兩個對象的hashcode相同會發生什么?

因為hashcode相同,所以它們的bucket位置相同,‘碰撞’會發生。這時將要插入的keyhashmap中與這個key的hashcode值相同的key通過equals判斷:

如果返回true,將視為同一個對象,會將新的value替換掉原來的value;

如果返回false,因為HashMap使 用鏈表存儲對象, 這個Entry(包含有鍵值對的Map.Entry對象)會存儲在鏈表中。

 

“如果兩個鍵的hashcode相同,你如何獲取值對象?”

當我們調用get()方法,HashMap會使用鍵對象的hashcode找到bucket位置,然后獲取值對象。如果有兩個值對象儲存在同一個bucket,找到bucket位置之后,會調用keys.equals()方法去找到鏈表中正確的節點, 最終找到要找的值對象

(補充回答)使用不可變的、聲明作final的對象,並且采用合適的equals()和 hashCode()方法的話,將會 減少碰撞的發生,提高效率。不可變性使得能夠緩存不同鍵的hashcode,這將提高整個獲取對象的速度, 使用 String,Interger這樣的wrapper類作為鍵是非常好的選擇。

如果HashMap的大小超過了負載因子(load factor)定義的容量,怎么辦?

默認的負載因子大小為0.75,也就是說,當一個map填滿了75%的bucket時候,和其它集合類(如ArrayList 等)一樣,將會創建原來HashMap大小的兩倍的bucket數組,來重新調整map的大小,並將原來的對象 放入新的bucket數組中。這個過程叫作rehashing,因為它調用hash方法找到新的bucket位置。

你了解重新調整HashMap大小存在什么問題嗎?

當多線程的情況下,可能產生條件競爭(race condition)。

當重新調整HashMap大小的時候,確實存在條件競爭,因為如果兩個線程都發現HashMap需要重新調整 大小了,它們會同時試着調整大小。在調 整大小的過程中,存儲在鏈表中的元素的次序會反過來,因為 移動到新的bucket位置的時候,HashMap並不會將元素放在鏈表的尾部,而是放在頭部, 這是為了避免 尾部遍歷(tail traversing)。如果條件競爭發生了,那么就死循環了。我個人認為在多線程的環境下使用 HashMap 是不合理的

 

回答過程中的細節問題:

為什么String, Interger這樣的wrapper類適合作為鍵?

String, Interger這樣的wrapper類作為HashMap的鍵是再適合不過了,而且String最為常用。因為String是不可變的,也是final 的,而且已經重寫了equals()和hashCode()方法了。其他的wrapper類也有這個特點。不可變性是必要的,因為為了要計算 hashCode(),就要防止鍵值改變,如果鍵值在放入時和獲取時返回不同的hashcode的話,那么就不能從HashMap中找到你想要的對象。不 可變性還有其他的優點如線程安全。如果你可以僅僅通過將某個field聲明成final就能保證hashCode是不變的,那么請這么做吧。因為獲取對象 的時候要用到equals()和hashCode()方法,那么鍵對象正確的重寫這兩個方法是非常重要的。如果兩個不相等的對象返回不同的 hashcode的話,那么碰撞的幾率就會小些,這樣就能提高HashMap的性能。

我們可以使用自定義的對象作為鍵嗎?

當然,你可能使用任何對象作為鍵,但是要想得到你想要的結果,他必須滿足一定的條件:

(1)重寫hashcode方法,在不重寫的情況下,hashcode()的返回值根據在Object類中的定義是返回的是根據地址在內存中的位置轉換成的int值,也就是任意兩個對象的hashcode()都不相同,因此存進hashmap的值就無法取出。例:

 

(2)作為只要它遵守了equals()和hashCode()方法的定義規則,並且當對象插入到Map中之 后將不會再改變了。如果這個自定義對象時不可變的,那么它已經滿足了作為鍵的條件,因為當它創建之后就已經不能改變了。

 

我們可以使用CocurrentHashMap來代替Hashtable嗎?

他是JDK 1.5引入的並發集合類,對於大型的、要求低延遲的電子商務系統來說非常的有用。

Hashtable和ConcurrentHashMap有什么分別呢?它們都可以用於多線程的環境,但是當Hashtable的大小增加到一定的時候,性能會急劇下降,因為迭代時需要被鎖定很長的時間。因為ConcurrentHashMap引入了分割,不論它變得多么大,僅僅需要鎖定map的某個部分,而其它的線程不需要等到迭代完成才能訪問map。簡而言之,在迭代的過程中,ConcurrentHashMap僅僅鎖定map的某個部分,而Hashtable則會鎖定整個map.ConcurrentHashMap其實采用了並發的思想,當某個鎖使用到的時候,僅僅是在這個鎖的控制范圍內其他的對象不可以訪問,在其他的部分,其他的對象仍然可以訪問。

 

HashMap與ConcurrentHashMap的區別

從JDK1.2起,就有了HashMap,HashMap相對於hashtable有很多優點,但是也有他的不足之處。他是線程不安全的,多線程操作時容易導致死鎖的發生。

在JDK1.5中,新增了concurrent包,從此Map也有安全的了。

 

與hashtable實現同步的方式不同,它引入了一個“分段鎖”的概念,具體可以理解為把一個大的Map拆分成N個小的Segment(類似HashTable),根據key.hashCode()來決定把key放到哪個Segment中。在ConcurrentHashMap中,就是把Map分成了N個Segment,put和get的時候,都是現根據key.hashCode()算出放到哪個Segment中

 

 

詳細解析 ConcurrentHashMap


免責聲明!

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



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