1. 程式人生 > >高併發程式設計系列:4大併發工具類的功能、原理、以及應用場景

高併發程式設計系列:4大併發工具類的功能、原理、以及應用場景

通常我們所說的併發包也就是java.util.concurrent,集中了Java併發工具類和併發容器等,今天主要介紹Java併發程式設計的工具類,我先從Java併發工具包談起。

01

併發工具包涵蓋範圍

1.併發工具類

提供了比synchronized更加高階的各種同步結構:包括CountDownLatch、CyclicBarrier、Semaphore等,可以實現更加豐富的多執行緒操作。

2.併發容器

提供各種執行緒安全的容器:最常見的ConcurrentHashMap、ConcurrentSkipListMap,實現執行緒安全的動態陣列CopyOnWriteArrayList等。

3.併發佇列

各種BlockingQueue的實現:常用的ArrayBlockingQueue、SynchorousQueue、特定場景的PriorityBlockingQueue。

4.Executor框架

可以建立各種不同型別的執行緒池,排程任務執行等,絕大部分情況下,不再需要自己從頭實現執行緒池和任務排程器。

02

常用的併發容器

1.ConcurrentHashMap

經常使用的併發容器,JDK 1.7和1.8的底層資料結構發生了變化(後續文章會詳解),這裡可以建議學習順序如下:從Java7 HashMap -> Java7 ConcurrentHashMap -> Java8 HashMap -> Java8 ConcurrentHashMap,這樣可以更好的掌握這個併發容器,畢竟都是從HashMap進化而來。

2.ConcurrentSkipListMap

在乎順序,需要對資料進行非常頻繁的修改

3.CopyOnWrite容器

CopyOnWrite容器即寫時複製的容器。從JDK1.5開始Java併發包裡提供了兩個使用CopyOnWrite機制實現的併發容器,CopyOnWriteArrayList和CopyOnWriteArraySet。

4.各種併發佇列的實現

如各種BlockedQueue實現,比較典型的ArrayBlockingQueue、SynchorousQueue。

03

常用的併發工具類

1.CountDownLatch

功能:

CountDownLatch是一個同步的輔助類,允許一個或多個執行緒,等待其他一組執行緒完成操作,再繼續執行。

原理

  • CountDownLatch是通過一個計數器來實現的,計數器的初始值為需要等待執行緒的數量。

eg:CountDownLatch c = new CountDownLatch(10); // 等待執行緒的數量為10

  • 主執行緒呼叫CountDownLatch的await()方法會阻塞當前執行緒(即:主執行緒在閉鎖上等待),直到計數器的值為0。

  • 當一個工作執行緒完成了自己的任務後,呼叫CountDownLatch的countDown()方法,計數器的值就會減1。

  • 當計數器值為0時,說明所有的工作執行緒都執行完了,此時,在閉鎖上等待的主執行緒就可以恢復執行任務。

應用場景:

倒數計時器

例如:一種典型的場景就是火箭發射。在火箭發射前,為了保證萬無一失,往往還要進行各項裝置、儀器的檢查。 只有等所有檢查完畢後,引擎才能點火。這種場景就非常適合使用CountDownLatch。

它可以使得點火執行緒,等待所有檢查執行緒全部完工後,再執行

使用方式:

static final CountDownLatch end = new CountDownLatch(10);end.countDown();  end.await();

2.CyclicBarrier

功能:

CyclicBarrier的字面意思是可迴圈使用(Cyclic)的屏障(Barrier)。它要做的事情是,讓一組執行緒到達一個屏障(也可以叫同步點)時被阻塞,直到最後一個執行緒到達屏障時,屏障才會開門,所有被屏障攔截的執行緒才會繼續執行。

和CountDownLatch相似,也是等待某些執行緒都做完以後再執行。

與CountDownLatch區別:

在於這個計數器可以反覆使用。比如,假設我們將計數器設定為10。那麼湊齊第一批1 0個執行緒後,計數器就會歸零,然後接著湊齊下一批10個執行緒。

原理:

1)CyclicBarrier是通過一個計數器來實現的,計數器的初始值為需要等待執行緒的數量。eg:CyclicBarrier c = new CyclicBarrier(2); // 等待執行緒的數量為2

2)每個執行緒呼叫CyclicBarrier的await()方法,使自己進入等待狀態。

3)當所有的執行緒都呼叫了CyclicBarrier的await()方法後,所有的執行緒停止等待,繼續執行。

使用方式:

public CyclicBarrier(int parties, Runnable barrierAction) 
barrierAction就是當計數器一次計數完成後,系統會執行的動作await()

3.訊號量Semaphore

功能

Java提供了經典訊號量Semaphore的實現,它通過控制一定數量的許可(permit)的方式,來達到限制通用資源訪問的目的。例如:控制併發的執行緒數。

原理:

1)Semaphore是通過一個計數器(記錄許可證的數量)來實現的,計數器的初始值為需要等待執行緒的數量。

eg:Semaphore s = new Semaphore(10); // 執行緒最大的併發數為10

2)執行緒通過acquire()方法獲取許可證(計數器的值減1),只有獲取到許可證才可以繼續執行下去,否則阻塞當前執行緒。

3)執行緒通過release()方法歸還許可證(計數器的值加1)。

說明:使用tryAcquire()方法可以立即得到執行的結果:嘗試獲取一個許可證,若獲取成功,則立即返回true,若獲取失敗,則立即返回false。

應用場景:

Semaphore可以用於做流量控制,特別是公用資源有限的應用場景,比如資料庫連線。

舉一個場景:例如在車站、機場等計程車時,當很多空出租車就位時,為防止過度擁擠,排程員指揮排隊等待坐車的隊伍一次進來5個人上車,等這5個人坐車出發,再放進去下一批。這和Semaphore的工作原理有些類似。

4.交換者Exchanger

功能

Exchanger(交換者)是一個用於執行緒間協作的工具類。Exchanger用於進行執行緒間的資料交換。

原理

它提供一個同步點,在這個同步點兩個執行緒可以交換彼此的資料。

這兩個執行緒通過exchange方法交換資料, 如果第一個執行緒先執行exchange方法,它會一直等待第二個執行緒也執行exchange,當兩個執行緒都到達同步點時,這兩個執行緒就可以交換資料,將本執行緒生產出來的資料傳遞給對方。

Exchanger的應用場景

Exchanger可以用於校對工作的場景。