CountDownLatch和CyclicBarrier都可以用来让一个线程等待其他线程执行完再继续执行

一、CountDownLatch

public class Test8 {

    static Logger LOG = LoggerFactory.getLogger(Test8.class);

    public static void main(String[] args) throws InterruptedException {
        LOG.info("start");
        CountDownLatch count = new CountDownLatch(2);//计数器初始值为2
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                count.countDown();
                LOG.info("t1 run");
            }
        });

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //计数器的值减1
                count.countDown();
                LOG.info("t2 run");
            }
        });

        t1.start();
        t2.start();
        //等待计数器的值边为0后主线程继续执行
        count.await();
        LOG.info("end");
    }
}

CountDownLatch用来让一个线程等待其余线程执行完后再继续执行,使用者调用await方法后就会开始等待

CountDownLatch的初始值创建时指定后就不能被修改,所以这个倒计时器是一次性的,减到0作用就完成了,不能被再次使用。

二、CyclicBarrier

它的作用:

让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最后一个线程到达屏障时,屏障才会开门,所有被屏障拦截的线程才会继续运行。

public class Test8 {

    static Logger LOG = LoggerFactory.getLogger(Test8.class);

    public static void main(String[] args) throws InterruptedException {
        LOG.info("start");
        CyclicBarrier cycleCount = new CyclicBarrier(2);
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                LOG.info("t1 run start");
                try {
                    Thread.sleep(2000);
                    cycleCount.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
                LOG.info("t1 run end");
            }
        });

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                LOG.info("t2 run start");
                try {
                    Thread.sleep(1000);
                    cycleCount.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
                LOG.info("t2 run end");
            }
        });

        t1.start();
        t2.start();

    }
}

上边的代码,cycleCount让线程t1或t2先执行await后都会让计数器的值减1然后开始等待,直到最后一个线程执行await让计数器的值变为0,就会唤醒阻塞的所有线程继续执行后续逻辑。

CyclicBarrier还有一个接收Runnable对象的构造方法,传递的Runnable对象会在计数器减为0其他调用await方法的线程都运行结束后被执行,常用来汇总其他线程的执行结果。

public class Test8 {

    static Logger LOG = LoggerFactory.getLogger(Test8.class);

    static AtomicInteger count = new AtomicInteger(0);

    public static void main(String[] args) throws InterruptedException {
        LOG.info("start");
        CyclicBarrier cycleCount = new CyclicBarrier(2, new Runnable() {
            @Override
            public void run() {
                LOG.info("其他线程都执行完了,count:{}",count.get());
            }
        });
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                LOG.info("t1 run start");
                try {
                    Thread.sleep(2000);
                    count.getAndIncrement();
                    cycleCount.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
                LOG.info("t1 run end");
            }
        });

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                LOG.info("t2 run start");
                try {
                    Thread.sleep(1000);
                    count.getAndIncrement();
                    cycleCount.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
                LOG.info("t2 run end");
            }
        });

        t1.start();
        t2.start();

    }
}

同时CyclicBarrier是一个可重用的计时器,当内部的计数器减为0后再次调用其await方法,计数器又会从初始值开始倒数让调用线程等待。

public static void main(String[] args) throws InterruptedException {
        LOG.info("start");
        CyclicBarrier cycleCount = new CyclicBarrier(2);
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                LOG.info("t1 run start");
                try {
                    Thread.sleep(2000);
                    cycleCount.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
                LOG.info("t1 run end");
            }
        });

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                LOG.info("t2 run start");
                try {
                    Thread.sleep(1000);
                    cycleCount.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
                LOG.info("t2 run end");
            }
        });

        t1.start();
        t2.start();
        t1.join();
        t2.join();
		// 当t1 t2运行结束后t3再调用await方法又会让t3进行等待;只到其他线程让cycleCount内部计数器
         // 变为0就会唤醒所有等待的线程。
        Thread t3 = new Thread(new Runnable() {
            @Override
            public void run() {
                LOG.info("t3 run start");
                try {
                    Thread.sleep(1000);
                    cycleCount.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
                LOG.info("t3 run end");
            }
        },"t3");

        Thread t4 = new Thread(new Runnable() {
            @Override
            public void run() {
                LOG.info("t4 run start");
                try {
                    Thread.sleep(1000);
                    cycleCount.await();
                } catch (InterruptedException | BrokenBarrierException e) {
                    e.printStackTrace();
                }
                LOG.info("t4 run end");
            }
        },"t3");
        t3.start();
        t4.start();

    }