HashMap、HashTable、ConcurrentHashMap、TreeMap、LinkedHashMap、WeakHashMap區別


1. HashMap

  標准鏈地址法實現(下圖)。數組方式存儲key/value,線程非安全,允許null作為keyvaluekey不可以重復,value允許重復,不保證元素迭代順序是按照插入時的順序,keyhash值是先計算keyhashcode值,然后再進行計算,每次容量擴容會重新計算所以keyhash值,會消耗資源,要求key必須重寫equalshashcode方法。默認初始容量16,加載因子0.75,擴容為舊容量乘2,查找元素快,如果key一樣則比較value,如果value不一樣,則按照鏈表結構存儲value。如果需要同步,可以用 CollectionssynchronizedMap方法(Map m = Collections.synchronizedMap(new HashMap(…));)。使HashMap具有同步的能力,或者使用ConcurrentHashMap

  

 

JDK 1.8之后,加入了static final int TREEIFY_THRESHOLD = 8;,當同一桶內元素個數超過8個,就會將鏈表結構進行樹化。

    /** * The bin count threshold for using a tree rather than list for a * bin. Bins are converted to trees when adding an element to a * bin with at least this many nodes. The value must be greater * than 2 and should be at least 8 to mesh with assumptions in * tree removal about conversion back to plain bins upon * shrinkage. */ static final int TREEIFY_THRESHOLD = 8;

2. HashTable

  線程安全,不允許有null的鍵和值,線程安全的,它在所有涉及到多線程操作的都加上了synchronized關鍵字來鎖住整個table,這就意味着所有的線程都在競爭一把鎖,在多線程的環境下,它是安全的,但是無疑是效率低下的。

3. ConcurrentHashMap

  HashTable有很多的優化空間,鎖住整個table這么粗暴的方法可以變相的柔和點,比如在多線程的環境下,對不同的數據集進行操作時其實根本就不需要去競爭一個鎖,因為他們不同hash值,不會因為rehash造成線程不安全,所以互不影響,這就是鎖分離技術,將鎖的粒度降低,利用多個鎖來控制多個小的table,這就是ConcurrentHashMap JDK1.7版本的核心思想。

JDK1.7的實現

在JDK1.7版本中,ConcurrentHashMap的數據結構是由一個Segment數組和多個HashEntry組成,如下圖所示:

  

 

  Segment數組的意義就是將一個大的table分割成多個小的table來進行加鎖,也就是上面的提到的鎖分離技術,而每一個Segment元素存儲的是HashEntry數組+鏈表,這個和HashMap的數據存儲結構一樣

JDK1.8的實現

  JDK1.8的實現已經摒棄了Segment的概念,而是直接用Node數組+鏈表+紅黑樹的數據結構來實現,並發控制使用SynchronizedCAS來操作,整個看起來就像是優化過且線程安全的HashMap,雖然在JDK1.8中還能看到Segment的數據結構,但是已經簡化了屬性,只是為了兼容舊版本。

  

4. TreeMap

  TreeMap實現SortMap接口,基於紅黑二叉樹的NavigableMap的實現,線程非安全,不允許nullkey不可以重復,value允許重復,存入TreeMap的元素應當實現Comparable接口或者實現Comparator接口,會按照排序后的順序迭代元素,兩個相比較的key不得拋出classCastException。主要用於存入元素的時候對元素進行自動排序,迭代輸出的時候就按排序順序輸出

5. LinkedHashMap

  LinkedHashMapHashMap的一個子類,保存了記錄的插入順序,在用Iterator遍歷LinkedHashMap時,先得到的記錄肯定是先插入的。也可以在構造時用帶參數,按照應用次數排序。在遍歷的時候會比HashMap慢,不過有種情況例外,當HashMap容量很大,實際數據較少時,遍歷起來可能會比LinkedHashMap慢,因為LinkedHashMap的遍歷速度只和實際數據有關,和容量無關,而HashMap的遍歷速度和他的容量有關。

6. WeakHashMap

  WeakHashMap,從名字可以看出它是某種 Map,允許null作為keyvalue(Both null values and the null key are supported.),非線程安全(this class is not synchronized)。它的特殊之處在於 WeakHashMap 里的entry可能會被GC自動刪除,即使程序員沒有調用remove()或者clear()方法。

更直觀的說,當使用 WeakHashMap 時,即使沒有顯示的添加或刪除任何元素,也可能發生如下情況:

  • 調用兩次size()方法返回不同的值;
  • 兩次調用isEmpty()方法,第一次返回false,第二次返回true
  • 兩次調用containsKey()方法,第一次返回true,第二次返回false,盡管兩次使用的是同一個key
  • 兩次調用get()方法,第一次返回一個value,第二次返回null,盡管兩次使用的是同一個對象。

  WeekHashMap的這個特點特別適用於需要緩存的場景。在緩存場景下,由於內存是有限的,不能緩存所有對象;對象緩存命中可以提高系統效率,但緩存MISS也不會造成錯誤,因為可以通過計算重新得到。

  要明白WeekHashMap的工作原理,還需要引入一個概念:弱引用(WeakReference)。Java中內存是通過GC自動管理的,GC會在程序運行過程中自動判斷哪些對象是可以被回收的,並在合適的時機進行內存釋放。GC判斷某個對象是否可被回收的依據是,是否有有效的引用指向該對象。如果沒有有效引用指向該對象(基本意味着不存在訪問該對象的方式),那么該對象就是可回收的。這里的“有效引用”並不包括弱引用。也就是說,雖然弱引用可以用來訪問對象,但進行垃圾回收時弱引用並不會被考慮在內,僅有弱引用指向的對象仍然會被GC回收

  WeakHashMap內部是通過弱引用來管理entry的,弱引用的特性對應到WeakHashMap上意味:將一對key, value放入到WeakHashMap里並不能避免該key值被GC回收,除非在WeakHashMap之外還有對該key的強引用


免責聲明!

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



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