JDK的併發容器及使用場景

最近在研究JUC,看到了很多的併發容器。它們的特性和使用場景是不一樣的。在這裏,總結一下
1 .HashTable
2 .ConcurrentHashMap
3 .ConcurrentSkipListMap
4 .CopyOnWriteArrayList
5 .Vector
6 .ConcurrentLinkedQueue
7 .ConcurrectSkipListSet
下面我們挨個介紹
HashTable:對外暴露的所有方法,幾乎都被synchronized修飾。synchronized是串行訪問的,所以可想而知,HashTable的性能非常低
但是它串行的訪問的方式非常適合於數據強一致性的場景,比如金融行業就需要強一致性
ConcurrentHashMap:jdk1.5提供,jdk1.8以前使用Segment分段鎖實現併發訪問,jdk1.8及以後,jdk使用鎖升級的方式對synchronized關鍵字進行了優化,所以jdk1.8的HashMap重新啓用synchronized搭配CAS方式重構了ConcurrentHashMap,進一步提升了性能。ConcurrentHashMap在put操作的時候加鎖,但是在get以及size操作時,沒有加鎖。所以get操作很可能無法讀到剛剛寫入的的數據。另外一個ConcurrentHashMap底層採用數組加鏈表的方式存儲元素,當鏈表的元素個數超過8個時,鏈表會轉換爲紅黑樹。併發情況下,紅黑樹的插入和刪除操作會涉及到一個平衡的問題,涉及到節點很多,對所資源的競爭會非常大。所以,ConcurrentHashMap適用於數據量不是很大,同時對數據的一致性要求不高的場合
ConcurrentSkipListMap:jdk1.6引入。用來替代單線程的TreeMap。ConcurrentSkipListMap內部採用跳躍表的數據結構。在處理數據時,鎖住的節點不多,非常適合於處理大數據量且存在大量增刪改查的場景(千萬級別的數據)
單線程情況下,TreeMap的性能比ConcurrentSkipListMap的性能一點也不差,所以我們在單線程情況下首選TreeMap

以上都是key-value的容器,下面我們說一下單值存儲的容器
Vector。Vector在jdk1.0就提供了。所有對外的方法都使用synchronized關鍵字修飾,性能極差。同樣適用於數據要求強一致性的場景
CopyOnWriteArryList:底層的實現機制是這樣的:
當需要寫數據時,將底層的數組複製一個副本。然後對副本進行寫入操作,最後再將原數組的引用指向該副本。數組使用volatile關鍵字修飾,保證了讀操作的可見性。數組的複製操作是非常耗費性能的。所以,CopyOnWriteArrayList適合於讀遠大於寫的場景,比如:電商中的黑名單
ConcurrentLinkedQueue。傳統的、無阻塞、FIFO隊列。該隊列基於鏈表實現,寫數據時,通過cas操作,新增和刪除操作非常快。所以適合於寫多讀少的場合,比如:搶購場景。。但是該隊列是無界的,使用時要注意內存溢出的情況
ConcurrentSkipListSet有序集合。由名字也可以看出,它的底層數據結構和ConcurrentSkipListMap一樣也是基於跳躍表設計。事實上,它的底層確實是由ConcurrentSkipListMap實現的,只不過只用到了key。它對應的單線程數據結構是TreeSet。平時沒有用過這個數據結構。不過,既然是由ConcurrentSkipListMap實現的,應該也是適用於大數據量的寫多讀少的場合

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