android基礎之Map系列

數組:內存存儲連續 佔用內存多 尋址容易,時間複雜度: 索引查找 (O(1)),按值查找(O(log(2)n)

鏈表: 內存存儲不連續 佔用內存少 插入與刪除方便,時間複雜度(O(n)) ,

爲了結合數組尋址容易與鏈表的插入刪除容易,HashTable應運而生;

 

java爲數據結構中的映射定義了一個接口java.util.Map;它有四個實現類,分別是HashMap 

Hashtable LinkedHashMap 和TreeMap.

HashMap: 數據結構:數組+鏈表+紅黑樹(或稱之爲鏈表的數組),HashMap裏面有一個Entry類(key,value,next),可以理解爲其存儲結構是一個線性數組(Entry[]),

 

put():

根據key的hashCode得到hash值,然後hash對Entry[].length取模得到下標index,在數組的index 下標位置處添加value,當然這時就要注意當hash值重複時就會發生hash衝突。

解決Hash衝突: 假設Entry[0] = A;進來了一個鍵值對B,其index值與A相同,這時讓B.next = A;

Entry[0] = B;...,這時就解決了hash衝突。也就是說數組中存儲的是最後插入的元素。

get():

根據key.hashCode得到hash值對Entry[]取模得到index,這時根據index得到所對應的鏈表或紅黑樹,然後根據equea()判斷key值是否相等,相等時返回該值,不相等時判斷下一個元素,直到該鏈表中再無元素。

 

區別:null值,安全性,同步,速度

 

總結:

 

Map: map用於存儲鍵值對,根據鍵得到值,鍵不允許重複(重複就覆蓋了),但允許值重複。

 

 

HashMap:hashMap是一個最常用的Map。它根據鍵的Hashcode值存儲數據,根據鍵可以直接得到它的值,具有很快的訪問速度,遍歷時,取得數據的順序都是完全隨機的。HashMap只允許一條記錄的鍵爲null,允許多個記錄的值爲null。HashMap不支持線程的同步,即任一時刻可以有多個線程操作HashMap;可能會導致數據不一致。(解決方法:使用SynchronizedMap或者ConcurrentHashMap)所以線程不安全,多個線程無法共享一個HashMap.。

 

WeakHashMap:WeakHashMap是一種改進的HashMap,它對key實行“弱引用”,當一個key不被外界所引用,則該Key會被GC回收。

 

HashTable: 與HashMap類似,不同點:不允許鍵或者值爲null,synchronized,支持線程同步,線程安全,多個線程可以共享一個HasTable,即任一時刻,只允許一個線程能寫HashTable,這也就導致了HashTable在寫入時比較慢。

 

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

 

TreeMap:TreeMap實現了SortMap的接口,能夠將它保存的記錄按照鍵排序,默認是升序排序。也可以指定排序的比較器,當用Iterator遍歷TreeMap時,得到的記錄是排過序的。

 

SynchronizedMap:hashMap存在線程安全問題,因此,在Collections類提供了一個方法返回一個同步版本的HashMap用於多線程環境,該方法返回一個SynchronizedMap實例。SynchronizedMap類是定義在Collection中的一個靜態內部類。他實現了Map接口,並對其中的每一個方法實現,通過Synchronized關鍵字進行了同步控制。但還是存在潛在的安全問題。

 

 

 

ConcurrentHashMap:ConcurrentHashMap提供了HashTable和HashMap以及SynchronizedMap中所不同的鎖機制。比起SynchronizedMap,它提供了好得多的併發性。多個讀操作幾乎總可以併發執行,同時進行的讀和寫操作也能併發執行,而同時進行的寫操作仍然可以不時的併發執行。HashTable採用的鎖機制是一次鎖定整個hash表,從而同一時刻只能由一個線程對其進行操作;

ConrrentHashMap採用的鎖機制是每一次鎖定一個桶。

ConcurrentHahMap默認將hash表分爲16個桶,諸如get、put、remove等尋常操作只鎖當前需要用到的桶。這樣一來,原本只能一個線程進入,現在卻能同時有16個寫線程進行執行,併發性的提升顯而易見。前面所說的16個線程指的是寫線程,而讀操作基本不需要用到鎖。只有在size等操作時纔會鎖定整個表。

 

在迭代方面,ConcurrentHashMap使用了一種不同的迭代方式。在這種迭代方式中,當Iterator被創建後集合在再發生改變就不會再是拋出ConcurrentModificationException,取而代之的是在改變時new新的數據從而不影響原有的數據,iterator完成後再將頭指針替換爲新的數據,這樣Iterator線程就可以使用原來老的數據,從而寫線程也可以併發的完成改變。

 

 

 

 

 

Hashmap與LinkedHashMap與TreeMap使用場景:

一般情況下,我們用的最多的是HashMap,在Map 中插入、刪除和定位元素,HashMap 是最好的選擇。但如果您要按自然順序或自定義順序遍歷鍵,那麼TreeMap會更好。如果需要輸出的順序和輸入的相同,那麼用LinkedHashMap 可以實現,它還可以按讀取順序來排列.

 

Hashmap與SynchronizedMap與ConcurrentHashMap使用場景:

一般情況下使用HashMap,但是HashMap線程不安全,所以在多線程的場景下使用SynchronizedMap,但是SynchronizedMap也存在一些潛在的安全問題(如迭代時數據更改),這時我們擁有更好的選擇concurrenthashMap。

 

擴展:

CopyOnWriteArrayList可以用於什麼應用場景?

答:CopyOnWriteArrayList用於讀多寫少的併發場景,比如白名單、黑名單。

CopyOnWrite容器即寫時複製的容器。通俗的理解是當我們往一個容器添加元素的時候,不直接往當前容器添加,而是先將當前容器進行Copy,複製出一個新的容器,然後新的容器裏添加元素,添加完元素之後,再將原容器的引用指向新的容器。這樣做的好處是我們可以對CopyOnWrite容器進行併發的讀,而不需要加鎖,因爲當前容器不會添加任何元素。所以CopyOnWrite容器也是一種讀寫分離的思想,讀和寫不同的容器。

CopyOnWriteArrayList(免鎖容器)的好處之一是多個迭代器同時遍歷和修改這個列表時,不會拋出ConcurrentModificationException。在CopyOnWriteArayList中,寫入將會導致創建整個底層數組的副本,而源數組將保留在原地,使得複製的數組在被修改時,讀取操作可以安全地執行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章