AQS同期コンポーネント--CountDown Latch


CountDown Latch
Count DownLatchはjava 1.5で導入されています。一緒に導入された同時工具類はCyclicBarrier、Semaphore、ConcerenthashMapとBlockingQueがあります。CountDownLatchというクラスは、他のスレッドがそれぞれの作業を完了するのを待ってスレッドを実行することができます。例えば、アプリケーションのメインスレッドは、フレームサービスを開始するスレッドがすべてのフレームサービスを開始した後に実行してほしい。CountDownLatchは一つのカウンタによって実現され、カウンタの初期値はスレッドの数である。一つのスレッドが自分のタスクを完了するたびに、カウンタの値は1を減算します。カウンタ値が0に達すると、すべてのスレッドがタスクを完了したことを表し、閉塞上で待機しているスレッドがタスクを再開することができます。
CountDownLatch類を呼び出したawait()メソッドは、他のスレッドがCountDown()を呼び出すまでカウンタの値を1つ減らし、カウンタの値が0になるとawait()メソッドを呼び出してブロック状態にあるスレッドが起動されて実行を継続します。カウンタはリセットできません。このクラスはスレッドを使用して、ある条件に達したら実行し続ける場合があります。並列計算など、計算量がとても大きいので、計算量を複数のスレッドに分割して計算し、結果をまとめます。
一つのCountdown Latchの例
@Slf4j
public class CountDownLatchExample1 {

    private final static int threadCount = 200;

    public static void main(String[] args) throws Exception {

        ExecutorService exec = Executors.newCachedThreadPool();

        final CountDownLatch countDownLatch = new CountDownLatch(threadCount);

        for (int i = 0; i < threadCount; i++) {
            final int threadNum = i;
            exec.execute(() -> {
                try {
                    test(threadNum);
                } catch (Exception e) {
                    log.error("exception", e);
                } finally {
                    countDownLatch.countDown();
                }
            });
        }
        countDownLatch.await();
        log.info("finish");
        exec.shutdown();
    }

    private static void test(int threadNum) throws Exception {
        Thread.sleep(100);
        log.info("{}", threadNum);
        Thread.sleep(100);
    }
}
私たちはスレッドの後にcountDownメソッドを呼び出して、logを実行する前にawaitメソッドを呼び出して、ログを印刷する時に必ずすべてのスレッドで実行し終わることを保証します。もし私たちがCountDownLatchを使わないと結果はどうなりますか?
@Slf4j
public class CountDownLatchExample1 {

    private final static int threadCount = 200;

    public static void main(String[] args) throws Exception {

        ExecutorService exec = Executors.newCachedThreadPool();

        final CountDownLatch countDownLatch = new CountDownLatch(threadCount);

        for (int i = 0; i < threadCount; i++) {
            final int threadNum = i;
            exec.execute(() -> {
                try {
                    test(threadNum);
                } catch (Exception e) {
                    log.error("exception", e);
                }
//                finally {
////                    countDownLatch.countDown();
//                }
            });
        }
//        countDownLatch.await();
        log.info("finish");
//        exec.shutdown();
    }

    private static void test(int threadNum) throws Exception {
        Thread.sleep(100);
        log.info("{}", threadNum);
        Thread.sleep(100);
    }
}
このコードの印刷の結果、最初からfinishが印刷されました。これはメインスレッドで実行されます。