Java中CountDownLatch進(jìn)行多線程同步詳解
CountDownLatch介紹
在前面的Java學(xué)習(xí)筆記中,總結(jié)了Java中進(jìn)行多線程同步的幾個方法:
1、synchronized關(guān)鍵字進(jìn)行同步。
2、Lock鎖接口及其實(shí)現(xiàn)類ReentrantLock、ReadWriteLock鎖實(shí)現(xiàn)同步。
3、信號量Semaphore實(shí)現(xiàn)同步。
其中,synchronized關(guān)鍵字和Lock鎖解決的是多個線程對同一資源的并發(fā)訪問問題。信號量Semaphore解決的是多副本資源的共享訪問問題。
今天,來學(xué)習(xí)一下Java中的另外一個多線程同步輔助類:CountDownLatch。官方文檔對CountDownLatch的解釋是:在完成一組正在其他線程中執(zhí)行的操作之前,它允許一個或多個線程一直等待。也就是說,CountDownLatch控制某個或者多個線程,讓它們等待多個線程完成某項任務(wù)后,再啟動。CountDownLatch主要是用來同步多個任務(wù)的執(zhí)行,區(qū)別于其他的synchronized關(guān)鍵字,鎖,信號量是用來同步共享資源的。
CountDownLatch實(shí)現(xiàn)原理簡介:
CountDownLatch內(nèi)部維護(hù)一個計數(shù)器,計數(shù)器的值為待完成的任務(wù)數(shù)N,需要等待這N個任務(wù)完成的線程調(diào)用
CountDownLatch的await()方法使自己進(jìn)入休眠等待狀態(tài)。
當(dāng)某一個任務(wù)線程完成某一個任務(wù)后調(diào)用CountDownLatch的countDown()方法來表示自己的任務(wù)已完成,此時CountDownLatch的計數(shù)器值減1,當(dāng)所有的任務(wù)完成式,計數(shù)器的值為0。當(dāng)計數(shù)器值為0時,CountDownLatch將喚醒所有因await()方法進(jìn)入休眠的線程。
CountDownLatch的使用:
CountDownLatch的使用主要有3點(diǎn):
1、CountDownLatch的聲明及初始化,在初始化時需要指定等待完成的任務(wù)數(shù)。
2、某一個任務(wù)完成時調(diào)用CountDownLatch的countDown()方法,向CountDownLatch報告自己的任務(wù)已經(jīng)完成,
3、需要等待任務(wù)完成的線程調(diào)用CountDownLatch的await()方法,調(diào)用后該線程將進(jìn)入休眠,并在所有任務(wù)數(shù)完成后CountDownLatch的計數(shù)器值為0時,因await()方法進(jìn)行休眠的線程將被喚醒。
在此本人在Java 7并發(fā)編程實(shí)戰(zhàn)手冊該書中的CountDownLatch使用示例的基礎(chǔ)上做了部分改進(jìn),來演示CountDownLatch的使用詳情:
模擬10個參會者和一個主持人參加的一個會以,每個參會者及主持人需要等待其他的參會者均到場簽到之后,才能開始會以并發(fā)言。為此,先創(chuàng)建一個會以管理的類VideoConference,其提供一個arrive()方法供參會者調(diào)用來進(jìn)行簽到。會議管理的擁有者是主持人,其等待每個參會者的簽到:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
public class VideoConference implements Runnable{ private final CountDownLatch countDownLatch; private int number; public VideoConference( int number) { this .number = number; this .countDownLatch = new CountDownLatch(number); //使用Number初始化其內(nèi)部的計數(shù)器,當(dāng)初始化完成后,不能再次初始化 } public void arrive(String name){ //每個需要同步的任務(wù),在任務(wù)完成時,需要調(diào)用該方法 countDownLatch.countDown(); //countDownLatch內(nèi)部的計數(shù)器減1 System.out.print( "arrive:" +name+ "\n" ); try { countDownLatch.await(); //await方法是線程進(jìn)入休眠,當(dāng)countDownLatch計數(shù)器為0時,將被喚醒 //線程被喚醒,在這里可以執(zhí)行一系列任務(wù) System.out.print( "name:" +name + " say:let's start..." + "\n" ); } catch (InterruptedException e){ e.printStackTrace(); } } public void run(){ System.out.print( "has arrive:" +(number-countDownLatch.getCount())+ "\n" ); try { countDownLatch.await(); //await方法是線程進(jìn)入休眠,當(dāng)countDownLatch計數(shù)器為0時,將被喚醒 //線程被喚醒,在這里可以執(zhí)行一系列任務(wù) System.out.print( "all arrived:" +(number-countDownLatch.getCount())+ "\n" ); } catch (InterruptedException e){ e.printStackTrace(); } } } |
創(chuàng)建一個參會者類Participant:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
public class Participant implements Runnable{ private VideoConference videoConference; private String name; public Participant(String name, VideoConference videoConference) { this .name = name; this .videoConference = videoConference; } public void run(){ try { //do something Thread.sleep( 50 ); // videoConference.arrive(name); } catch (InterruptedException e){ e.printStackTrace(); } } public static void main(String[] args){ VideoConference videoConference = new VideoConference( 10 ); Thread videoThread = new Thread(videoConference); videoThread.start(); for ( int i= 0 ; i< 10 ; i++){ Thread thread = new Thread( new Participant( "participant:" +i,videoConference)); thread.start(); } } } |
Participant類中的main函數(shù)首先創(chuàng)建了一個需要10個參會者參加的一個會議,之后,創(chuàng)建了10個參會者并逐個簽到,在10個參會者都簽到之后,每個參會者及主持人將被"喚醒"并發(fā)言。
總結(jié):
CountDownLatch類解決的是多線程間的同步等待、任務(wù)協(xié)調(diào)問題,應(yīng)用在如在啟動某個程序的主功能前,需要前置完成配置環(huán)境檢查、網(wǎng)絡(luò)檢查等多個子任務(wù)等類似的場景。在Java中,除了使用CountDownLatch來實(shí)現(xiàn)多線程間的同步等待以外,還可以使用柵欄技術(shù)CyclicBarrier來實(shí)現(xiàn)多線程間的同步等待、任務(wù)協(xié)調(diào)。
感謝閱讀,希望能幫助到大家,謝謝大家對本站的支持!
原文鏈接:http://blog.csdn.net/zbc1090549839/article/details/53464902