1. 程式人生 > >java中Map有哪些實現類和使用場景

java中Map有哪些實現類和使用場景

     Java中的map是一個很重要的集合,他是一個介面,下面繼承它實現了多個實現類,這些類各有千秋,各自有個各自的優點和缺點,先上圖。


     map的主要特點是鍵值對的形式,一一對應,且一個key只對應1個value。其常用的map實現類主要有HashMap、HashTable、TreeMap、ConcurrentHashMap、LinkedHashMap、weakHashMap等等。

1、HashMap

2、HashTable

       hashTable是執行緒安全的一個map實現類,它實現執行緒安全的方法是在各個方法上添加了synchronize關鍵字。但是現在已經不再推薦使用HashTable了

,因為現在有了ConcurrentHashMap這個專門用於多執行緒場景下的map實現類,其大大優化了多執行緒下的效能。

3、ConcurrentHashMap

       如果你經常參加面試,一定會被問到這個map實現類,這個map實現類是在jdk1.5中加入的,其在jdk1.6/1.7中的主要實現原理是segment段鎖,它不再使用和HashTable一樣的synchronize一樣的關鍵字對整個方法進行枷鎖,而是轉而利用segment段落鎖來對其進行加鎖,以保證Map的多執行緒安全。

     其實可以理解為,一個ConcurrentHashMap是由多個HashTable組成,所以它允許獲取不用段鎖的執行緒同時持有該資源,segment有多少個,理論上就可以同時有多少個執行緒來持有它這個資源。

     其預設的segment是一個數組,預設長度為16。也就是說理論商可以提高16倍的效能。


      但是要注意咯大笑,在JAVA的jdk1.8中則對ConcurrentHashMap又再次進行了大的修改,取消了segment段鎖欄位,採用了CAS+Synchronize技術來保障執行緒安全。底層採用陣列+連結串列+紅黑樹的儲存結構,也就是和HashMap一樣。這裡注意Node其實就是儲存一個鍵值對的最基本的物件。其中Value和next都是使用的volatile關鍵字進行了修飾,以確保執行緒安全。這裡推薦一下大神的Volatile的深入理解篇,寫的非常好http://www.cnblogs.com/xrq730/p/7048693.html


     在插入元素時,會首先進行CAS判定,如果OK就插入其中,並將size+1,但是如果失敗了,就會通過自旋鎖自旋後再次嘗試插入,直到成功。

    所謂的CAS也就是compare And Swap,即在更改前先對記憶體中的變數值和你指定的那個變數值進行比較,如果相同這說明在這期間沒有被修改過,則可以進行修改,而如果不一樣了,則就要停止修改,否則就會覆蓋掉其他的引數。即記憶體值a,舊值b,和要修改的值c,如果這裡a=b,那麼就可以進行更新,就可以將記憶體值a修改成c。否則就要終止該更新操作。

    為什麼這裡會用volatile進行修飾,我在其他部落格找到了答案。主要有兩個用處:

1、令這個被修飾的變數的更新具有可見性,一旦該變數遭到了修改,其他執行緒立馬就會知道,立馬放棄自己在自己工作記憶體中持有的該變數值,轉而重新去主記憶體中獲取到最新的該變數值。

2、產生了記憶體屏障,這裡volatile可以保證CPU在執行程式碼時保證,所有被volatile中被修飾的之前的一定在之前被執行,也就是所謂的“指令重排序”。

    同hashMap一樣,在JDK1.8中,如果連結串列中儲存的Entry超過了8個則就會自動轉換連結串列為紅黑樹,提高查詢效率。

4、TreeMap

     TreeMap也是一個很常用的map實現類,因為他具有一個很大的特點就是會對Key進行排序,使用了TreeMap儲存鍵值對,再使用iterator進行輸出時,會發現其預設採用key由小到大順序輸出鍵值對,如果想要按照其他的方式來排序,需要重寫也就是override 它的compartor介面。此處引用一下其他大神的程式碼:

 1 import java.util.Comparator;
 2 import java.util.Iterator;
 3 import java.util.Set;
 4 import java.util.TreeMap;
 5 
 6 
 7 public class Compare {
 8     public static void main(String[] args) {
 9         TreeMap<String,Integer> map = new TreeMap<String,Integer>(new xbComparator());
10         map.put("key_1", 1);
11         map.put("key_2", 2);
12         map.put("key_3", 3);   
13         Set<String> keys = map.keySet();
14         Iterator<String> iter = keys.iterator();
15         while(iter.hasNext())
16         {
17                 String key = iter.next();
18                 System.out.println(" "+key+":"+map.get(key));
19         }
20     }
21 }
22 class xbComparator implements Comparator
23 {
24     public int compare(Object o1,Object o2)
25     {
26         String i1=(String)o1;
27         String i2=(String)o2;
28         return -i1.compareTo(i2);
29     }
30 }

    另外,TreeMap底層的儲存結構也是一顆紅黑樹。大笑是不是發現好多都是紅黑樹,沒錯因為紅黑樹查詢效率高,只有O(lgn)。它是一種自平衡的二叉查詢樹。在每次插入和刪除節點時,都可以自動調節樹結構,以保證樹的高度是lgn。

5、LinkedHashMap

    LinkedHashMap它的特點主要在於linked,帶有這個字眼的就表示底層用的是連結串列來進行的儲存。相對於其他的無序的map實現類,還有像TreeMap這樣的排序類,linkedHashMap最大的特點在於有序,但是它的有序主要體現在先進先出FIFIO上。沒錯,LinkedHashMap主要依靠雙向連結串列和hash表來實現的。


    仔細看,這裡雖然在計算hashcode時還是發生了hash衝突,採用了鏈地址法解決了衝突,但是這裡的Entry物件是採用雙向連結串列儲存的,每個Entry都有一個after和before的屬性。當插入一個entry時,如果發生了衝突,就可以將新的Entry插入Entry連結串列中的頭部,但是按照雙向連結串列的角度來說,又會將該Entry插入到雙向連結串列的尾部。

6、weakHashMap

    首先,weakHashMap它是一個“弱鍵”,它的Key值和Value都可以是null,而且其Map中如果這個Key值指向的物件沒被使用,此時觸發了GC,該物件就會被回收掉的。其原理主要是使用的WeakReference和ReferenceQueue實現的,其key就是weakReference,而ReferenceQueue中儲存了被回收的 Key-Value。

    如果當其中一個Key-Value不再使用被回收時,就將其加入ReferenceQueue佇列中。當下次再次呼叫該WeakHashMap時,就會去更新該map,比如ReferenceQueue中的key-value,將其中包含的key-value全部刪除掉。這就是所謂的“自動刪除”。