這裡主要是簡單介紹幾種比較常見的並發容器,目的是梳理一下。由於每一個類的底層實現都是非常複雜的,用到了很多精妙的多線程的技巧,限於篇幅和水平,就不做深入的探討。紙上得來終覺淺,只有多加實踐,多看源碼,才能深入理解它們。
一、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),設定過高會照成空間的浪費,設定過低會降低並發性。這種對調優的把握是要通過對底層實現的深刻理解和不斷的實踐積累才能擷取的。