Java實戰小技巧(四):併發編程之CountDownLatch類

CountDownLatch是Java 5新增加的一個併發工具類,可以使一個線程等待其他線程執行完畢後再執行。CountDownLatch是通過一個計數器來實現的,計數器的初始值是線程的數量,每當一個線程執行完畢後,計數器的值就-1,當計數器的值爲0時,表示所有線程都執行完畢,然後被阻塞的線程就可以繼續執行了。CountDownLatch計數器的操作是原子操作,同時只能有一個線程去操作這個計數器。

CountDownLatch是一種共享鎖,就是允許多個線程同時獲取一個鎖,一個鎖可以同時被多個線程擁有。共享鎖(S鎖)又稱讀鎖,若事務T對數據對象A加上S鎖,則事務T可以讀A但不能修改A,其他事務只能再對A加S鎖,而不能加X鎖,直到T釋放A上的S鎖。這保證了其他事務可以讀A,但在T釋放A上的S鎖之前不能對A做任何修改。

CountDownLatch類的方法如下:

定義 描述
CountDownLatch(int count) CountDownLatch類初始化,設置計數器的初始值,即需等待的線程數量。
void await() 使一個線程開始等待,直到CountDownLatch計數器的值爲零後,再繼續向下執行。
boolean await(long timeout, TimeUnit unit) 功能同上,但可以設置等待超時時間,超時後返回false,並繼續向下執行。未超時返回true。
void countDown() 線程執行完畢後調用,CountDownLatch計數器的值減1。
long getCount() 獲取當前CountDownLatch計數器的值。

CountDownLatch簡單應用示例:

CountDownLatch latch = new CountDownLatch(2);
創建線程1
創建線程2
latch.await();
計數爲0時喚醒
執行線程1
latch.countDown();
執行線程2
latch.countDown();

如上圖,主線程調用await()後,除非計數器值爲0,否則會一直阻塞休眠。當所有任務執行完後,主線程被喚醒,繼續向下執行。

共享鎖應用示例:

CountDownLatch latch = new CountDownLatch(2);
創建線程1
創建線程2
創建線程3
創建線程4
執行線程4
latch.await();
計數爲0時喚醒
執行線程3
latch.await();
計數爲0時喚醒
執行線程1
latch.countDown();
執行線程1
latch.countDown();

CountDownLatch類可以在任意多個地方執行await()方法,不同線程也可以,一切只依據狀態值,不受限於任何的場景。如上圖,在線程3和線程4分別調用了await(),當狀態值爲0後,這兩個線程將會繼續執行,但執行順序無法保證。

在Java 5提供的併發包下,有一個AbstractQueuedSynchronizer抽象類,也叫AQS,此類根據大部分併發共性作了一些抽象,便於開發者實現如排他鎖、共享鎖、條件等待等更高級的業務功能,它通過使用CAS和隊列模型完成抽象任務。

當多個線程調用await()時,會按調用順序加入等待喚醒的同步隊列。狀態值爲0後,將以鏈式喚醒機制按加入等待隊列的順序喚醒線程。如下圖:

喚醒
喚醒
通知狀態
通知狀態
空節點(head)
線程3節點
線程4節點(tail)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章