Java并發(fā)工具類(閉鎖CountDownLatch)

閉鎖是一種同步工具類,可以延遲線程的進度直到其到達終止狀態(tài)。

CountDownLatch是一種靈活的閉鎖實現(xiàn),它可以使一個或者多個線程等待一組事件的發(fā)生。

閉鎖狀態(tài)包含一個計數(shù)器,該計數(shù)器被初始化為一個正數(shù),表示需要等待的事件數(shù)量。countDown方法遞減計數(shù)器,表示已經(jīng)有一個事件已經(jīng)發(fā)生了。而await方法等待計數(shù)器達到0,這表示所有需要等待的事件都已經(jīng)發(fā)生。如果計數(shù)器的值非0,那么await會一直阻塞直到計數(shù)器為0,或者等待中的線程中斷或者超時。
下面,我們以經(jīng)典的運動員賽跑舉例:


Runner

我們在這里設置了兩個門,一個是開始門,一個是結(jié)束門。

  • 開始門: 所有運動員處于準備狀態(tài),等待教練的槍聲。這時候運動員為n個,槍響只需要一聲,等待的這一聲槍響到了,開始門也就打開了,所有運動員開始跑。
  • 結(jié)束門: 教練等待所有運動員,當最后一個運動員也沖破底線,教練才能宣布所有人到達終點,這時候是教練等待n個運動員,直到n為0。

下面我們根據(jù)具體的代碼來演示CountDownLatch的用法:

package concurrency;

import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

class Runner implements Runnable {
    private static int counter = 0;
    private final int id = counter++;
    private static Random rand= new Random(47);
    private final CountDownLatch start_latch;
    private final CountDownLatch end_latch;

    public Runner(CountDownLatch start_latch, CountDownLatch end_latch) {
        this.start_latch = start_latch;
        this.end_latch = end_latch;
    }

    @Override
    public void run() {
        try {
            start_latch.await();  //所有運動員都在準備狀態(tài)中,等待教練釋放開始門
            try {
                doWork();  //每個人跑步的時間不同
                end_latch.countDow n();  //跑完后,告訴教練跑完了
            } catch (InterruptedException e) {
                System.out.println("Interrupted Runner" + id);
            }
        } catch (InterruptedException e) {
            System.out.println("Interrupted Runner" + id);
        }
    }

    public void doWork() throws InterruptedException {
        TimeUnit.MILLISECONDS.sleep(rand.nextInt(2000));
        System.out.println(this + "completed");
    }

    @Override
    public String toString() {
        return String.format("%1$-3d", id);
    }
}

class Coach implements Runnable {
    private final CountDownLatch start_latch;
    private final CountDownLatch end_latch;

    public Coach(CountDownLatch start_latch, CountDownLatch end_latch) {
        this.start_latch = start_latch;
        this.end_latch = end_latch;
    }

    @Override
    public void run() {
        start_latch.countDown();  //教練釋放了開始門,運動員們都開始跑
        System.out.println("Coach say: Ready!!!!  Go!!!!");
        try {
            end_latch.await();  //當結(jié)束門的count down減為0時,教練宣布所有人都跑完了。
            System.out.println("All runner passed the end point");
        } catch (InterruptedException ex) {
            System.out.println(this + " interrupted");
        }
    }
}

public class TestRunner {
    private static final int SIZE = 10;
    public static void main(String[] args) {
        ExecutorService exec = Executors.newCachedThreadPool();
        CountDownLatch startGate = new CountDownLatch(1);
        CountDownLatch endGate = new CountDownLatch(SIZE);
        for (int i = 0; i < SIZE; i++) {
            exec.execute(new Runner(startGate, endGate));
        }
        exec.execute(new Coach(startGate, endGate));
        exec.shutdown();
    }
}

CountDownLatch強調(diào)的是一個線程(或多個)需要等待另外的n個線程干完某件事情之后才能繼續(xù)執(zhí)行。 上述例子,Coach線程是裁判,10個Runner是跑步的。運動員先準備,裁判喊跑,運動員才開始跑(這是第一次同步,對應startGate)。10個人誰跑到終點了,countdown一下,直到10個人全部到達,裁判喊停(這是第二次同步,對應endGate)。
最后運行結(jié)果如下:

Coach say: Ready!!!! Go!!!!
7 completed
9 completed
5 completed
8 completed
2 completed
0 completed
6 completed
4 completed
1 completed
3 completed
All runner passed the end point

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內(nèi)容