同步類容器和併發類容器

2021-09-26 15:13:34 字數 2787 閱讀 8507

同步類容器都是執行緒安全的,但在某些場景下可能需要加鎖來保護復合操作。復合類操作。如:迭代(反覆訪問元素,遍歷完容器中所有的元素)、跳轉(根據指定的順序找到當前元素的下乙個元素)、以及條件運算。這些復合操作在多執行緒併發地修改容器時,可能會表現出意外的行為,最經典的便是concurrentmodificationexception,原因是當容器迭代的過程中,被併發的修改了內容,這是由於早期迭代器設計的時候並沒有考慮併發修改的問題。

同步類容器如古老的vector、 hash table。這些容器的同步功能其實都是有jdk的collections.synchronized***等工廠方法去建立實現的。其底層的機制無非就是用傳統的synchronized關鍵字對每個公用的方法都進行同步,使得每次只能有乙個執行緒訪問容器的狀態。這很明顯不滿足我們今天網際網路時代高併發的需求,在保證執行緒安全的同時,也必須要有足夠好的效能。

jdk5.0以後提供了多種併發類容器來替代同步類容器從而改善效能。同步類容器的狀態都是序列化的。他們雖然實現了執行緒安全,但是嚴重降低了併發性,在多執行緒環境時,嚴重降低了應用程式的吞吐量。

併發類容器是專門針對併發設計的,使用concurrenthashmap來代替給予雜湊的傳統的hashtable,而且在concurrenthashmap中,新增了一些常見復合操作的支援。以及使用了copyonwritearraylist代替voctor,併發的copyonwritearrayset, 以及併發的

queue, concurrentlinkedqueue和linkedblockingqueue, 前者是高效能的佇列,後者是以阻塞形式的佇列,具體實現queue還有很多, 例如arrayblockingqueue、priorityblockingqueue、synchronousqueue等。

concurrentmap介面下有倆個重要的實現:

(1)concurrenthashmap

(2)concurrentskiplistmap (支援併發排序功能,彌補concurrenthashmap)

concurrenthashmap內部使用段(segment)來表示這些不同的部分,每個段其實就是-乙個小的hashtable,它們有自己的鎖。只要多個修改操作發生在不同的段上,它們就可以併發進行。把乙個整體分成了16個段(segment)。也就是最高支援16個執行緒的併發修改操作。這也是在多執行緒場景時減小鎖的粒度從而降低鎖競爭的一種方案。並且**中大多共享變數使用volatile關鍵字宣告,目的是第一時間獲取修改的內容,效能非常好。

copy-on-write簡稱cow,是一種用於程式設計中的優化策略。

jdk裡的cow容器有兩種: copyonwritearraylist和copyonwritearrayset,cow容器非常有用,可以在非常多的併發場景中使用到。

什麼是copyonwrite容器?

copyonwrite容器即寫時複製的容器。通俗的理解是當我們往乙個容 器新增元素的時候,不直接往當前容器新增,而是先將當前容器進行copy,複製出一乙個新的容器,然後新的容器裡新增元素,新增完元素之後,再將原容器的引用指向新的容器。這樣做的好處是我們可以對copyonwrite容器進行併發的讀,而不需要加鎖,因為當前容器不會新增任何元素。所以copyonwrite容器也是一種讀寫分離的思想,讀和寫不同的容器。

在併發佇列上jdk提供了兩套實現,乙個是以concurrentlinkedqueue為代表的高效能佇列,乙個是以blockingqueue介面為代表的阻塞佇列,無論哪種都繼承自queue。

concurrentlinkedqueue:是乙個適用於高併發場景下的佇列,通過無鎖的方式,實現了高併發狀態下的高效能,通常concurrentlinkedqueue 效能好於blockingqueue。它是乙個基於鏈結節點的無界線程安全佇列。該佇列的元素遵循先進先出的原則。頭是最先加入的,尾是最近加入的,該佇列不允許null元素。

concurrentlinkedqueue重要方法:

add()和offer()都是加入元素的方法(在concurrentlinkedqueue中,這兩個方法沒有任何區別)

pol()和peek()都是取頭元素節點,區別在於前者會刪除元素,後者不會。

arrayblockingqueue:基於 陣列的阻塞佇列實現,在arrayblockingqueue內部, 維護了乙個定長陣列,以便快取佇列中的資料物件,其內部沒實現讀寫分離,也就意味著生產和消費不能完全並行,長度是需要定義的,可以指定先進先出或者先進後出,也叫有界佇列,在很多場合非常適合使用。

linkedblockingqueue:基於鍊錶的阻塞佇列,同arrayblockingqueue類似, 其內部也維持著乙個資料緩衝佇列(該佇列由乙個鍊錶構成),linkedblockingqueue之所以能夠高效的處理併發資料,是因為其內部實現採用分離鎖(讀寫分離兩個鎖) ,從而實現生產者和消費者操作的完全並行執行。他是乙個無界佇列。

synchronousqueue : -種沒有緩衝的佇列,生產者產生的資料直接會被消費者獲取並消費。

priorityblockingqueue:基於優先順序的阻塞佇列(優先順序的判斷通過建構函式傳入的compator物件來決定,也就是說傳入佇列的物件必須實現comparable介面) ,在實現priorityblockingqueue時,內部控制線程同步的鎖採用的是公平鎖,他也是- -個無界的佇列。

delayqueue:帶有延遲時間的queue,其中的元素只有當其指定的延遲時間到了,才能夠從佇列中獲取到該元素。delayqueue中的元素必須實現delayed介面,delayqueue是-個沒有大小限制的佇列,應用場景很多,比如對快取超時的資料進行移除、任務 超時處理、空閒連線的關閉等等。

同步類容器和併發類容器

同步類容器都是執行緒安全的,但是某些場景下可能需要加鎖來保護復合操作。復合類操作如 迭代 反覆訪問元素,遍歷完容器中所有的元素 跳轉 根據指定的順序找到當前元素的下乙個元素 以及條件運算。這些復合操作在多執行緒併發地修改容器時,可能會表現出意外的行為,最經典的便是concurrentmodifica...

同步類容器和併發類容器

同步類容器都是執行緒安全的,同步容器類包括 vector 和 hashtable,二者都是早期 jdk 的一部分,此外還包括在 jdk1.2 當中新增的一些功能相似的類,這些同步的封裝類是由 collections.synchronized 等工廠方法建立的。但在某些場景下可能需要加鎖來保護復合操作...

同步類容器和併發類容器

一 同步類容器 同步類容器都是執行緒安全的,但在某些場景下可能需要加鎖來保護復合操作。復合類操作如 迭代 反覆訪問元素,遍歷完容器中的所有元素 跳轉 根據指定的順序找到當前元素的下乙個元素 以及條件運算。這些復合操作在多執行緒併發的修改容器時,可能會表現出意外的行為,最經典的便是concurrent...