天天看點

Java線程-閉鎖(CountDownLatch)

CountDownLatch有時被稱為“閉鎖”,其作用相當于一扇門:在CountDownLatch達到結束狀态之前,這扇門一直是關閉的,并且沒有任何線程能通過,當到達結束狀态時,這扇門會打開并允許所有的線程通過。當CountDownLatch到達結束狀态後,将不會再改變狀态,是以這扇門将永遠保持打開狀态。CountDownLatch可以用來確定某些活動直到其它活動都完成後才繼續執行。

她與CyclicBarrier有什麼樣的差別呢?

(1)、CountDownLatch是不可重置的,是以無法重用;CyclicBarrier沒用這種限制,可以重用。

(2)、CountDownLatch的組合是countDown/await,無論是一個線程還是多個線程,隻要countDown足夠的次數,才能繼續下一步,進行後面的任務,它是屬于事件驅動的;而CyclicBarrier使用了await,隻有當所有的并發線程調用了await,完成所有的任務,才能繼續接下來的任務,CyclicBarrier側重的是線程,而不是事件。

用CountDownLatch實作排隊場景:

假設有10個人排隊,我們将其分成5個人一批,通過CountDownLatch來協調批次。

public class Thread_CountDownLatch {

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch latch = new CountDownLatch(6);
        for (int i = 0; i < 5; i++) {
            Thread t = new Thread(new FirstBatchWorker(latch));
            t.start();
        }
        for (int i= 0; i < 5; i++) {
            Thread t = new Thread(new SecondBatchWorker(latch));
            t.start();
        }
        // 注意:這裡是示範目的的邏輯,并不是推薦的協調方式
        while (latch.getCount() != 1) {
            Thread.sleep(100L);
        }
        System.out.println("Wait for first batch finish");
        latch.countDown();
    }
    static class FirstBatchWorker implements Runnable {
        private CountDownLatch latch;
        public FirstBatchWorker(CountDownLatch latch) {
            this.latch = latch;
        }
        @Override
        public void run() {
            System.out.println("First batch executed!");
            latch.countDown();
        }
    }
    static class SecondBatchWorker implements Runnable {
        private CountDownLatch latch;
        public SecondBatchWorker(CountDownLatch latch) {
            this.latch = latch;
        }
        @Override
        public void run() {
            try {
                latch.await();
                System.out.println("Second batch executed!");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
           

CountDownLatch的排程方式相對簡單,後一批次的線程進行await,等待前一批countDown足夠多次。這個例子也從側面展現出了它的局限性,雖然它也能夠支援10個人排隊的情況,但是因為不能重用,如果要支援更多人排隊,就不能依賴一個CountDownLatch進行了,其編譯運作輸出如下:

First batch executed!
First batch executed!
First batch executed!
First batch executed!
First batch executed!
Wait for first batch finish
Second batch executed!
Second batch executed!
Second batch executed!
Second batch executed!
Second batch executed!
           

繼續閱讀