高併發程式設計系列: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可以用於校對工作的場景。