同步容器和併發容器總結
什麼是同步容器?
同步容器通過synchronized關鍵字修飾容器保證同一時刻內只有一個執行緒在使用容器,從而使得容器執行緒安全。synchronized的意思是同步,它體現在將多執行緒變為序列等待執行。(但注意一點,複合操作不能保證執行緒安全。舉例:A執行緒第一步獲取尾節點,第二步將尾結點的值加1,但在A執行緒執行完第一步的時候,B執行緒刪除了尾節點,在A執行緒執行第二步的時候就會報空指標)
什麼是併發容器?
併發容器指的是允許多執行緒同時使用容器,並且保證執行緒安全。而為了達到儘可能提高併發,Java併發工具包中採用了多種優化方式來提高併發容器的執行效率,核心的就是:鎖、CAS(無鎖)、COW(讀寫分離)、分段鎖。
同步容器
1.Vector
Vector和ArrayList一樣實現了List介面,其對於陣列的各種操作和ArrayList一樣,區別在於Vertor在可能出現執行緒不安全的所有方法都用synchronized進行了修飾。
2.Stack
Stack是Vertor的子類,Stack實現的是先進後出的棧。在出棧入棧等操作都進行了synchronized修飾。
3.HashTable
HashTable實現了Map介面,它實現的功能HashMap基本一致(HashTable不可存null,而HashMap的鍵和值都可以存null)。區別在於HashTable使用了synchronized修飾了方法。
4.Collections提供的同步集合類
- List list = Collections.synchronizedList(new ArrayList());
- Set set = Collections.synchronizedSet(new HashSet());
- Map map = Collections.synchronizedMap(new HashMap());
其實以上三個容器都是Collections通過代理模式對原本的操作加上了synchronized同步。而synchronized的同步粒度太大,導致在多執行緒處理的效率很低。所以在JDK1.5的時候推出了併發包下的併發容器,來應對多執行緒下容器處理效率低的問題。
併發容器
1.CopyOnWriteArrayList
CopyOnWriteArrayList相當於實現了執行緒安全的ArrayList,它的機制是在對容器有寫入操作時,copy出一份副本陣列,完成操作後將副本陣列引用賦值給容器。底層是通過ReentrantLock來保證同步。但它通過犧牲容器的一致性來換取容器的高併發效率(在copy期間讀到的是舊資料)。所以不能在需要強一致性的場景下使用。
2.CopyOnWriteArraySet
CopyOnWriteArraySet和CopyOnWriteArrayList原理一樣,它是實現了CopyOnWrite機制的Set集合。
3.ConcurrentHashMap
ConcurrentHashMap相當於實現了執行緒安全的HashMap。其中的key是無序的,並且key和value都不能為null。在JDK8之前,ConcurrentHashMap採用了分段鎖機制來提高併發效率,只有在操作同一分段的鍵值對時才需要加鎖。到了JDK8之後,摒棄了鎖分段機制,改為利用CAS演演算法。
4.ConcurrentSkipListMap
ConcurrentSkipListMap相當於實現了執行緒安全的TreeMap。其中的key是有序的,並且key和value都不能為null。它採用的跳躍表的機制來替代紅黑樹。為什麼不繼續使用紅黑樹呢?因為紅黑樹在插入或刪除節點的時候需要旋轉調整,導致需要控制的粒度較大。而跳躍表使用的是連結串列,利用無鎖CAS機制實現高併發執行緒安全。
5.ConcurrentSkipListSet
ConcurrentSkipListSet和ConcurrentSkipListMap原理一樣,它是實現了高併發執行緒安全的TreeSet。
Queue型別
阻塞型
1.ArrayBlockingQueue
ArrayBlockingQueue是採用陣列實現的有界阻塞執行緒安全佇列。如果向已滿的佇列繼續塞入元素,將導致當前的執行緒阻塞。如果向空佇列獲取元素,那麼將導致當前執行緒阻塞。採用ReentrantLock來保證在併發情況下的執行緒安全。
2.LinkedBlockingQueue
LinkedBlockingQueue是一個基於單向連結串列的、範圍任意的(其實是有界的)、FIFO 阻塞佇列。訪問與移除操作是在隊頭進行,新增操作是在隊尾進行,並分別使用不同的鎖進行保護,只有在可能涉及多個節點的操作才同時對兩個鎖進行加鎖。
3.PriorityBlockingQueue
PriorityBlockingQueue是一個支援優先順序的無界阻塞佇列。預設情況下元素採用自然順序升序排列。也可以自定義類實現compareTo()方法來指定元素排序規則,
4.DelayQueue
DelayQueue是一個內部使用優先順序佇列實現的無界阻塞佇列。同時元素節點資料需要等待多久之後才可被訪問。取資料佇列為空時等待,有資料但延遲時間未到時超時等待。
5.SynchronousQueue
SynchronousQueue沒有容量,是一個不儲存元素的阻塞佇列,會直接將元素交給消費者,必須等佇列中的新增元素被消費後才能繼續新增新的元素。相當於一條容量為1的傳送帶。
6.LinkedTransferQueue
LinkedTransferQueue是一個有連結串列組成的無界傳輸阻塞佇列。它集合了ConcurrentLinkedQueue、SynchronousQueue、LinkedBlockingQueue等優點。具體機制較為複雜。
7.LinkedBlockingDeque
LinkedBlockingDeque是一個由連結串列結構組成的雙向阻塞佇列。所謂雙向佇列指的是可以從佇列的兩端插入和移出元素。
非阻塞型
1.ConcurrentLinkedQueue
ConcurrentLinkedQueue是執行緒安全的無界非阻塞佇列,其底層資料結構是使用單向連結串列實現,入隊和出隊操作是使用我們經常提到的CAS來保證執行緒安全。