1. 程式人生 > 其它 >java.util.concurrent java併發工具包

java.util.concurrent java併發工具包

1. 目的

java.util.concurrent 的目的就是要實現 Collection 框架對資料結構所執行的併發操作。通過提供一組可靠的、高效能併發構建塊,開發人員可以提高併發類的執行緒安全、可伸縮性、效能、可讀性和可靠性

1、BlockingQueue 阻塞佇列

java.util.concurrent裡面的BlockingQueue介面代表一個執行緒安全的佇列。
BlockingQueue通常用於一個執行緒生成物件,另一個執行緒消費。


生產執行緒持續生成新的物件並且把它插入都佇列直到佇列達到它容納的上限。如果這個阻塞佇列達到容量上限,生產執行緒再嘗試插入新的物件時會阻塞。它會一直阻塞直到一個消費執行緒從佇列中取走一個物件。

消費執行緒會持續從阻塞佇列中取出物件然後處理它們。如果一個消費執行緒嘗試從一個空的佇列中取物件,它就會被阻塞直到一個生產執行緒向佇列中放入一個物件為止。


2、BlockingDeque 阻塞雙端佇列

BlockingDeque介面代表一個雙端佇列,它對於插入與取出的操作都是執行緒安全的。

BlockingDeque可以這樣被使用,如果所有執行緒都同時既生產也消費同一個佇列的元素。也同樣適用於生產執行緒需要在佇列兩端插入,消費執行緒需要從佇列兩端取出。

一個執行緒生產元素並且可以將它們插入佇列的兩端。如果雙端隊列當前是滿的,這個插入執行緒將會被阻塞直到一個消費執行緒從佇列取出一個元素,當消費執行緒從中取的時候也是類似的情況。

3、延遲佇列 DelayQueue

DelayQueue 實現了 BlockingQueue 介面。
DelayQueue 對元素進行持有直到一個特定的延遲到期。注入其中的元素必須實現 java.util.concurrent.Delayed 介面,該介面定義
DelayQueue 將會在每個元素的 getDelay() 方法返回的值的時間段之後才釋放掉該元素。如果返回的是 0 或者負值,延遲將被認為過期,該元素將會在 DelayQueue 的下一次 take 被呼叫的時候被釋放掉。
傳遞給 getDelay 方法的 getDelay 例項是一個列舉型別,它表明了將要延遲的時間段。

4、同步佇列 SynchronousQueue

SynchronousQueue 類實現了 BlockingQueue 介面。
SynchronousQueue 是一個特殊的佇列,它的內部同時只能夠容納單個元素。如果該佇列已有一元素的話,試圖向佇列中插入一個新元素的執行緒將會阻塞,直到另一個執行緒將該元素從佇列中抽走。同樣,如果該佇列為空,試圖向佇列中抽取一個元素的執行緒將會阻塞,直到另一個執行緒向佇列中插入了一條新的元素

5、執行緒安全集合類

執行緒安全集合類(ConcurrentHashMap、CopyOnWriteArrayList 和 CopyOnWriteArraySet)。 這些類的目的是提供高效能、高度可伸縮性、執行緒安全的基本集合型別版本。

6、併發導航對映 ConcurrentNavigableMap

java.util.concurrent.ConcurrentNavigableMap 是一個支援併發訪問的 java.util.NavigableMap,它還能讓它的子 map 具備併發訪問的能力。所謂的 "子 map" 指的是諸如 headMap(),subMap(),tailMap() 之類的方法返回的 map。 headMap(T toKey) 方法返回一個包含了小於給定 toKey 的 key 的子 map。
如果你對原始 map 裡的元素做了改動,這些改動將影響到子 map 中的元素(譯者注:map 集合持有的其實只是物件的引用)。 tailMap(T fromKey) 方法返回一個包含了不小於給定 fromKey 的 key 的子 map。
如果你對原始 map 裡的元素做了改動,這些改動將影響到子 map 中的元素(譯者注:map 集合持有的其實只是物件的引用)。 subMap(key1,key2) 方法返回原始 map 中,鍵介於 from(包含) 和 to (不包含) 之間的子 map。

7、計數器CountDownLatch(執行緒等待另一個執行緒執行)

java.util.concurrent.CountDownLatch 是一個併發構造,它允許一個或多個執行緒等待一系列指定操作的完成。
CountDownLatch 以一個給定的數量初始化。countDown() 每被呼叫一次,這一數量就減一。執行緒通過呼叫 await() 方法,執行緒可以阻塞等待這一數量到達零。

8、柵欄 CyclicBarrier

java.util.concurrent.CyclicBarrier 類是一種同步機制,它能夠對處理一些演算法的多個執行緒實現同步。 換句話講,它就是一個所有執行緒必須等待的一個柵欄,直到所有執行緒都到達這裡,然後所有執行緒才可以繼續向下執行。 滿足以下任何條件都可以讓等待 CyclicBarrier 的執行緒釋放:
  • 最後一個執行緒也到達 CyclicBarrier(呼叫 await())
  • 當前執行緒被其他執行緒打斷(其他執行緒呼叫了這個執行緒的 interrupt() 方法)
  • 其他等待柵欄的執行緒被打斷
  • 其他等待柵欄的執行緒因超時而被釋放
  • 外部執行緒呼叫了柵欄的 CyclicBarrier.reset() 方法

9、交換機 Exchanger

java.util.concurrent.Exchanger 類表示一種兩個執行緒可以進行互相交換物件。

兩個執行緒通過一個 Exchanger 交換物件。
交換物件的動作由 Exchanger 的兩個 exchange() 方法的其中一個完成

10、訊號量 Semaphore

java.util.concurrent.Semaphore 類是一個計數訊號量。這就意味著它具備兩個主要方法:
  • acquire()
  • release()
計數訊號量由一個指定數量的 "許可" 初始化。每呼叫一次 acquire(),一個許可會被呼叫執行緒取走。每呼叫一次 release(),一個許可會被返還給訊號量。因此,在沒有任何 release() 呼叫時,最多有 N 個執行緒能夠通過 acquire() 方法,N 是該訊號量初始化時的許可的指定數量。這些許可只是一個簡單的計數器。這裡沒啥奇特的地方。
訊號量主要有兩種用途:
  1. 保護一個重要(程式碼)部分防止一次超過 N 個執行緒進入。
  2. 在兩個執行緒之間傳送訊號。

11、執行者服務 ExecutorService

java.util.concurrent.ExecutorService 介面表示一個非同步執行機制,使我們能夠在後臺執行任務。因此一個 ExecutorService 很類似於一個執行緒池。實際上,存在於 java.util.concurrent 包裡的 ExecutorService 實現就是一個執行緒池實現。

12、執行緒池執行者 ThreadPoolExecutor

java.util.concurrent.ThreadPoolExecutor 是 ExecutorService 介面的一個實現。ThreadPoolExecutor 使用其內部池中的執行緒執行給定任務(Callable 或者 Runnable)。
ThreadPoolExecutor 包含的執行緒池能夠包含不同數量的執行緒。池中執行緒的數量由以下變數決定:
  • corePoolSize
  • maximumPoolSize
當一個任務委託給執行緒池時,如果池中執行緒數量低於 corePoolSize,一個新的執行緒將被建立,即使池中可能尚有空閒執行緒。
如果內部任務佇列已滿,而且有至少 corePoolSize 正在執行,但是執行執行緒的數量低於 maximumPoolSize,一個新的執行緒將被建立去執行該任務

13、定時執行者服務 ScheduledExecutorService

java.util.concurrent.ScheduledExecutorService 是一個 ExecutorService, 它能夠將任務延後執行,或者間隔固定時間多次執行。 任務由一個工作者執行緒非同步執行,而不是由提交任務給 ScheduledExecutorService 的那個執行緒執行。

14、使用 ForkJoinPool 進行分叉和合並

ForkJoinPool 在 Java 7 中被引入。它和ExecutorService很相似,除了一點不同。ForkJoinPool 讓我們可以很方便地把任務分裂成幾個更小的任務,這些分裂出來的任務也將會提交給 ForkJoinPool。任務可以繼續分割成更小的子任務,只要它還能分割。 分叉:將一個任務分成幾個任務 合併:將幾個任務的執行結果合併成一個結果

ForkJoinPool

ForkJoinPool 是一個特殊的執行緒池,它的設計是為了更好的配合 分叉-和-合併 任務分割的工作。ForkJoinPool 也在 java.util.concurrent 包中,其完整類名為 java.util.concurrent.ForkJoinPool。 RecursiveAction 是一種沒有任何返回值的任務。它只是做一些工作,比如寫資料到磁碟,然後就退出了。 RecursiveTask 是一種會返回結果的任務。它可以將自己的工作分割為若干更小任務,並將這些子任務的執行結果合併到一個集體結果。

15、鎖 Lock

java.util.concurrent.locks.Lock 是一個類似於 synchronized 塊的執行緒同步機制。但是 Lock 比 synchronized 塊更加靈活、精細。

Lock 和 synchronized 程式碼塊的主要不同點

一個 Lock 物件和一個 synchronized 程式碼塊之間的主要不同點是:
  • synchronized 程式碼塊不能夠保證進入訪問等待的執行緒的先後順序。
  • 你不能夠傳遞任何引數給一個 synchronized 程式碼塊的入口。因此,對於 synchronized 程式碼塊的訪問等待設定超時時間是不可能的事情。
  • synchronized 塊必須被完整地包含在單個方法裡。而一個 Lock 物件可以把它的 lock() 和 unlock() 方法的呼叫放在不同的方法裡
Lock 介面具有以下主要方法:
  • lock()
  • lockInterruptibly()
  • tryLock()
  • tryLock(long timeout, TimeUnit timeUnit)
  • unlock()
lock() 將 Lock 例項鎖定。如果該 Lock 例項已被鎖定,呼叫 lock() 方法的執行緒將會阻塞,直到 Lock 例項解鎖。
lockInterruptibly() 方法將會被呼叫執行緒鎖定,除非該執行緒被打斷。此外,如果一個執行緒在通過這個方法來鎖定 Lock 物件時進入阻塞等待,而它被打斷了的話,該執行緒將會退出這個方法呼叫。
tryLock() 方法試圖立即鎖定 Lock 例項。如果鎖定成功,它將返回 true,如果 Lock 例項已被鎖定該方法返回 false。這一方法永不阻塞。
tryLock(long timeout, TimeUnit timeUnit) 的工作類似於 tryLock() 方法,除了它在放棄鎖定 Lock 之前等待一個給定的超時時間之外。

unlock() 方法對 Lock 例項解鎖。一個 Lock 實現將只允許鎖定了該物件的執行緒來呼叫此方法。其他(沒有鎖定該 Lock 物件的執行緒)執行緒對 unlock() 方法的呼叫將會拋一個未檢查異常(RuntimeException)。

16、讀寫鎖 ReadWriteLock

java.util.concurrent.locks.ReadWriteLock 讀寫鎖是一種先進的執行緒鎖機制。它能夠允許多個執行緒在同一時間對某特定資源進行讀取,但同一時間內只能有一個執行緒對其進行寫入。
讀寫鎖的理念在於多個執行緒能夠對一個共享資源進行讀取,而不會導致併發問題。併發問題的發生場景在於對一個共享資源的讀和寫操作的同時進行,或者多個寫操作併發進行。

ReadWriteLock 鎖規則

一個執行緒在對受保護資源在讀或者寫之前對 ReadWriteLock 鎖定的規則如下:

    • 讀鎖:如果沒有任何寫操作執行緒鎖定 ReadWriteLock,並且沒有任何寫操作執行緒要求一個寫鎖(但還沒有獲得該鎖)。因此,可以有多個讀操作執行緒對該鎖進行鎖定。
    • 寫鎖:如果沒有任何讀操作或者寫操作。因此,在寫操作的時候,只能有一個執行緒對該鎖進行鎖定。

17、原子性布林 AtomicBoolean

AtomicBoolean 類為我們提供了一個可以用原子方式進行讀和寫的布林值,它還擁有一些先進的原子性操作,比如 compareAndSet()。AtomicBoolean 類位於 java.util.concurrent.atomic 包,完整類名是為 java.util.concurrent.atomic.AtomicBoolean。 compareAndSet() 方法允許你對 AtomicBoolean 的當前值與一個期望值進行比較,如果當前值等於期望值的話,將會對 AtomicBoolean 設定一個新值。compareAndSet() 方法是原子性的,因此在同一時間之內有單個執行緒執行它。

18、原子性整型 AtomicInteger

AtomicInteger 類為我們提供了一個可以進行原子性讀和寫操作的 int 變數,它還包含一系列先進的原子性操作,比如 compareAndSet()。AtomicInteger 類位於 java.util.concurrent.atomic 包,因此其完整類名為 java.util.concurrent.atomic.AtomicInteger。

19、原子性長整型 AtomicLong

AtomicLong 類為我們提供了一個可以進行原子性讀和寫操作的 long 變數,它還包含一系列先進的原子性操作,比如 compareAndSet()AtomicLong 類位於 java.util.concurrent.atomic 包,因此其完整類名為 java.util.concurrent.atomic.AtomicLong

20、原子性引用型物件 AtomicReference

AtomicReference 提供了一個可以被原子性讀和寫的物件引用變數。原子性的意思是多個想要改變同一個 AtomicReference 的執行緒不會導致 AtomicReference 處於不一致的狀態。AtomicReference 還有一個 compareAndSet() 方法,通過它你可以將當前引用於一個期望值(引用)進行比較,如果相等,在該 AtomicReference 物件內部設定一個新的引用。 AtomicReference 類具備了一個很有用的方法:compareAndSet()。compareAndSet() 可以將儲存在 AtomicReference 裡的引用於一個期望引用進行比較,如果兩個引用是一樣的(並非 equals() 的相等,而是 == 的一樣),將會給 AtomicReference 例項設定一個新的引用。
如果 compareAndSet() 為 AtomicReference 設定了一個新的引用,compareAndSet() 將返回 true。否則 compareAndSet() 返回 false。 摘自: https://www.jianshu.com/p/4c24e246400f https://blog.csdn.net/defonds/article/details/44021605 http://tutorials.jenkov.com/java-concurrency/index.html#java-concurrency-study-guide