Java多執行緒——併發容器簡介
這裡主要是簡單介紹幾種比較常見的併發容器,目的是梳理一下。由於每一個類的底層實現都是非常複雜的,用到了很多精妙的多執行緒的技巧,限於篇幅和水平,就不做深入的探討。紙上得來終覺淺,只有多加實踐,多看原始碼,才能深入理解它們。
一、ConcurrentHashMap
提供高併發性的執行緒安全的HashMap,實現了的HashMap的功能,並且實現了介面ConcurrentMap所定義的原子的putIfAbsent, remove和replace方法。ConcurrentHashMap把整個雜湊表分成多個segment,主要通過鎖分段技術減小了鎖的粒度,降低了衝突,從而提高了併發性。在實際的應用中,散列表一般是讀多寫少。ConcurrentHashMap 就針對讀操作做了大量的優化,運用了很多併發技巧,如不可變物件和使用volatile保證記憶體可見性,這樣,在大多數情況下讀操作甚至無需加鎖也能獲得正確的值。
另外還有ConcurrentSkipListMap/Set,實現了NavigableMap。插入之後的元素是有序的,插入,讀取,刪除的期望效率是log(n)。
二、CopyOnWriteArrayList
是執行緒安全的ArrayList,其所有寫操作都是通過對底層陣列進行一次新的複製來實現的,代價昂貴,適合讀多寫少的情況。另外,正是由於它通過複製的實現方式,CopyOnWriteArrayList提供了一種特別的功能:快照。如果你恰好有這樣的需求,CopyOnWriteArrayList將會是一個很好的選擇。
三、ConcurrentLinkedQueue
執行緒安全的基於Linked List 實現的非阻塞的無限佇列。提供非實時資料。
四、BlockingQueue系列
Queue是適合生產消費模式的資料結構。顧名思義,實現這個介面的都是阻塞佇列。
成員有:LinkedBlockingQueue、DelayQueue、LinkedTransferQueue、ArrayBlockingQueue、SynchronousQueue、PriorityBlockingQueue……
五、總結
不同的資料結構有不同的特點和作用,結合實際生產中的場景使用合適的資料結構是很重要的。我大概總結了一下幾個比較有特徵的:
1. 需要獲取快照而非實時的資訊時使用的資料結構。
2. 生產消費模式中大量使用的資料結構。
3. 讀多寫少的時候,對針對讀取進行了優化(可能導致弱一致性)的資料結構。
另外,在現實使用中的應該考慮到實際的併發性,從而為併發容器設計合適的引數。比如所ConcurrentHashMap的concurrentLevel(預設值為16),設定過高會照成空間的浪費,設定過低會降低併發性。這種對調優的把握是要通過對底層實現的深刻理解和不斷的實踐積累才能獲取的。