博客已遷移到CSDN《https://blog.csdn.net/qq_33375499》
1、Map:Map是所有map集合的頂級父接口,用於key/value形式的鍵值對,其中每一個key都映射到一個值,key不能重復。
2、TreeMap:該map將存儲的鍵值對進行默認排序,並且還能夠指定排序的比較器,是線程不安全的。TreeMap不允許鍵值為null。
// 指定比較器進行排序 Map map = new TreeMap(new Comparator(){ Public int compare(obj1, obj2){...} });
3、HashMap:這也是我們平時開發中最常用的map,底層實現為數組+鏈表,它根據鍵key的HashCode值存儲數據,可以使用get(key)來獲取鍵對應的值,是線程不安全的。HashMap允許存在一條鍵為null的記錄。在數據量小的時候,HashMap是以鏈表的模式存儲數據;當數據量變大后,為了進行快速查找,會將這個鏈表變為紅黑樹來進行保存,使用key的哈希值來進行查找。
4、Hashtable:與HashMap類似,不同的是,Hashtable是線程安全的,在進行插入是會比HashMap慢,並且key和value的值均不允許為null。對個線程同時訪問Hashtable對象時,第一個線程獲取鎖后,會引發其他線程進行等待,知道第一個線程釋放掉鎖。
5、LinkedHashMap:該map保證了對面在插入值得順序,在查詢遍歷的時候會比HashMap慢,是線程不安全的。允許key和value均為空。
6、ConcurrentHashMap:該map對象時線程安全的,與Hashtable不同的是,ConcurrentHashMap采用了分段鎖技術,沒有同Hashtable一樣鎖住全部數據,而是鎖定線程訪問的那一段數據。對個線程在訪問不同段數據時就不會存在等待。
ConcurrentHashMap的主干是Segment數組。沒有Segment就相當於一個小的HashTable,知道不修改訪問同一個Segment上的數據就不會存在並發問題。
(盜用大佬的一張圖片)
Segment是一種可重入鎖,繼承ReentranLock類。下面簡單介紹一下ReentranLock與synchronized的區別:
- Synchronized是一個同步鎖。當一個線程A訪問synchronized修飾的代碼塊時,線程A就會獲取該代碼塊的鎖,如果這時存在其他線程范圍該代碼塊時,將會阻塞,但是不影響這些線程訪問其他非同步代碼塊。
- ReentranLock是可重入鎖。由構造方法可知,該鎖支持兩種鎖模式,公平鎖和非公平鎖。默認是非公平的。
公平鎖:當線程A獲取訪問該對象,獲取到鎖后,此時內部存在一個計數器num+1,其他線程想訪問該對象,就會進行排隊等待(等待隊列最前一個線程處於待喚醒狀態),直到線程A釋放鎖(num = 0),此時會喚醒處於待喚醒狀態的線程進行獲取鎖的操作,一直循環。如果線程A再次嘗試獲取該對象鎖是,會檢查該對象鎖釋放已經被占用,如果被占用,會做一次是否為當前線程占用鎖的判斷,如果是內部計數器num+1,並且不需要進入等待隊列,而是直接回去當前鎖。
非公平鎖:當線程A在釋放鎖后,等待對象的線程會進行資源競爭,競爭成功的線程將獲取該鎖,其他線程繼續睡眠。
公平鎖是嚴格的以FIFO的方式進行鎖的競爭,但是非公平鎖是無序的鎖競爭,剛釋放鎖的線程很大程度上能比較快的獲取到鎖,隊列中的線程只能等待,所以非公平鎖可能會有“飢餓”的問題。但是重復的鎖獲取能減小線程之間的切換,而公平鎖則是嚴格的線程切換,這樣對操作系統的影響是比較大的,所以非公平鎖的吞吐量是大於公平鎖的,這也是為什么JDK將非公平鎖作為默認的實現。
對於Map的遍歷,建議使用entrySet迭代器方式,在進行大量級數據時,效率會高很多。
以上都是個人學習總計,歡迎各位大佬進行評閱