Java併發編程中級篇(三):使用CountDownLatch控制多線程併發等待

你是否遇到這這樣一種狀況,咱們要舉行一個視頻會議,有若干的參會人員,須要等待全部的人員到齊後視頻會議才能開始。java

爲了解決這個問題,Java API提供了一個線程同步輔助類CountDownLatch,使用這個輔助類可讓線程等待其它線程完成一組操做後才能執行,不然就一直等待。這個類使用一個整形參數來初始化,這個整形參數表明着等待其餘線程的數量,使用await()方法讓線程開始等待其餘線程執行完畢,每個線程執行完畢後後調用countDown()方法,這個方法會讓CountDownLatch內部的計數器減1,當計數器變爲0的時候,CountDownLatch類將喚醒全部調用await()方法並進入WAITING狀態線程。併發

下面咱們來完成這個視頻會議的例子:dom

建立視頻會議線程類VideoConference,並聲明一個CountDownLatch屬性controller來控制視頻會議線程等待全部參會者到齊。會議線程啓動後會調用await()方法並進入等待狀態,每個參會者到達後代用arrive()方法,並把controller中的計數器減1,當計數器等於0的時候會議線程繼續執行。ide

public class VideoConference implements Runnable{
    private final CountDownLatch controller;

    public VideoConference(int number) {
        controller = new CountDownLatch(number);
    }

    public void arrive(String name) {
        System.out.printf("%s has arrived.\n", name);
        controller.countDown();
        System.out.printf("VideoConference: Waiting for %d participants.\n", controller.getCount());
    }

    @Override
    public void run() {
        System.out.printf("VidwoConference: Initialization: %d participants.\n", controller.getCount());

        try {
            controller.await();
            System.out.printf("VidwoConference: All the participants have come.\n");
            System.out.printf("VidwoConference: Let's start...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

建立參會者線程類Participant,這個類持有會議類的引用,啓動後用一個隨機休眠時間來模擬與會者到達所需的時間,休眠結束後代用會議類的arrive(name)方法告訴會議類,與會者到達並把CountDownLatch計數器減1。this

public class Participant implements Runnable{
    private String name;
    private VideoConference videoConference;

    public Participant(String name, VideoConference videoConference) {
        this.name = name;
        this.videoConference = videoConference;
    }

    @Override
    public void run() {
        long duration = (long) (Math.random() * 10);
        try {
            TimeUnit.SECONDS.sleep(duration);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        videoConference.arrive(name);
    }
}

實現主方法類,這裏咱們建立並移動一個視頻會議,規定參會者有10我的。而後咱們啓動10個參會者線程,當全部參會者都到達後,視頻會議開始執行。線程

public class Main {
    public static void main(String[] args) {
        VideoConference videoConference = new VideoConference(10);
        Thread threadConference = new Thread(videoConference);
        threadConference.start();

        Thread[] threads = new Thread[10];
        for (int i = 0; i < 10; i++) {
            threads[i] = new Thread(new Participant("P-" + i, videoConference));
        }

        for (int i = 0; i < 10; i++) {
            threads[i].start();
        }
    }
}

查看控制檯日誌,咱們看到每次有一個參會者到達均可以調用getCount()方法來獲取計數器的值。日誌

VidwoConference: Initialization: 10 participants.
P-0 has arrived.
VideoConference: Waiting for 9 participants.
P-4 has arrived.
VideoConference: Waiting for 8 participants.
P-2 has arrived.
VideoConference: Waiting for 7 participants.
P-5 has arrived.
VideoConference: Waiting for 6 participants.
P-8 has arrived.
VideoConference: Waiting for 5 participants.
P-3 has arrived.
VideoConference: Waiting for 4 participants.
P-6 has arrived.
VideoConference: Waiting for 3 participants.
P-1 has arrived.
VideoConference: Waiting for 2 participants.
P-7 has arrived.
VideoConference: Waiting for 1 participants.
P-9 has arrived.
VideoConference: Waiting for 0 participants.
VidwoConference: All the participants have come.
VidwoConference: Let's start...

注意,CountDownLatch並非用來保護共享資源同步訪問的,而是用來控制併發線程等待的。而且CountDownLatch只容許進入一次,一旦內部計數器等於0,再調用這個方法將不起做用,若是還有第二次併發等待,你還得建立一個新的CountDownLatch。code

相關文章
相關標籤/搜索