• CountDownLatch 和 CyclicBarrier 的基本使用


      CountDownLatch 和 CyclicBarrier 是并发编程中常用的辅助类,两者使用上有点类似,但又有不同。

    一、CountDownLatch

      CountDownLatch 可是实现类似计数器的功能,比如一个线程 A 需要等待其余多个任务执行完毕后才能执行,此时可以使用这个工具类。 

      构造器:

    public CountDownLatch(int count) { }

      主要方法:

    public void await() throws InterruptedException { };   // 调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
    public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };  // 和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
    public void countDown() { };  // 将count值减1

      示例方法:

    public static void main(String[] args) {
    
        final CountDownLatch latch = new CountDownLatch(2);
    
        new Thread() {
            @Override
            public void run() {
                try {
                    System.out.println("子线程" + Thread.currentThread().getName() + "正在执行");
                    Thread.sleep(3000);
                    System.out.println("子线程" + Thread.currentThread().getName() + "执行完毕");
                    latch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    
        new Thread() {
            @Override
            public void run() {
                try {
                    System.out.println("子线程" + Thread.currentThread().getName() + "正在执行");
                    Thread.sleep(3000);
                    System.out.println("子线程" + Thread.currentThread().getName() + "执行完毕");
                    latch.countDown();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    
        try {
            System.out.println("等待2个子线程执行完毕...");
            latch.await();
            System.out.println("2个子线程已经执行完毕");
            System.out.println("继续执行主线程");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    View Code

      执行结果: 

    子线程Thread-0正在执行
    等待2个子线程执行完毕...
    子线程Thread-1正在执行
    子线程Thread-1执行完毕
    子线程Thread-0执行完毕
    2个子线程已经执行完毕
    继续执行主线程
    二、CyclicBarrier

      CyclicBarrier 可以称为回环栅,可以实现所有线程同时执行某动作的效果。比如跑步运动员在比赛前需要进行准备工作,等所有运动员都准备完毕后,同时开始比赛。

      构造器:

    public CyclicBarrier(int parties) { }  // 设置线程数量
    public CyclicBarrier(int parties, Runnable barrierAction) { }  // 设置线程数量,并设置所有线程 await 执行完毕后的方法
     

      主要方法:

    public int await() throws InterruptedException, BrokenBarrierException { };  // 挂起线程,直至所有线程达到 barrier 状态再执行
    public int await(long timeout, TimeUnit unit)throws InterruptedException,BrokenBarrierException,TimeoutException { };  // 同上,挂起线程,等待一定的时间

       示例方法:

    public class CyclicBarrierTest {
    
        public static void main(String[] args) {
            CyclicBarrier barrier = new CyclicBarrier(3, new Runnable() {
                @Override
                public void run() {
                    System.out.println("所有运动员准备完毕,倒计时3秒后比赛开始...我是裁判:" + Thread.currentThread().getName()
                        + ",当前时间:" + System.currentTimeMillis());
                }
            });
    
            new Competition(barrier, "张三").start();
            new Competition(barrier, "李四").start();
            new Competition(barrier, "王五").start();
        }
    
        /**
         * 跑步比赛内容,所有人准备工作完成后,起跑
         */
        static class Competition extends Thread {
    
            private CyclicBarrier cyclicBarrier;
    
            private String name;
    
            public Competition(CyclicBarrier cyclicBarrier, String name) {
                this.cyclicBarrier = cyclicBarrier;
                this.name = name;
            }
    
            @Override
            public void run() {
                int time = new Random().nextInt(10);
                System.out.println(name + "开始准备工作,预计耗时:" + time + "秒");
                try {
                    // 准备中
                    Thread.sleep(time * 1000);
                    System.out.println(name + "准备完成,等待其他运动员完成");
                    cyclicBarrier.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (BrokenBarrierException e) {
                    e.printStackTrace();
                }
                // 起跑倒计时
                try {
                    Thread.sleep(3000);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                System.out.println(name + "已经起跑...当前时间:" + System.currentTimeMillis());
            }
        }
    
    }
    View Code

      执行结果:

    张三开始准备工作,预计耗时:5秒
    王五开始准备工作,预计耗时:2秒
    李四开始准备工作,预计耗时:6秒
    王五准备完成,等待其他运动员完成
    张三准备完成,等待其他运动员完成
    李四准备完成,等待其他运动员完成
    所有运动员准备完毕,倒计时3秒后比赛开始...我是裁判:Thread-1,当前时间:1548768695636
    张三已经起跑...当前时间:1548768698637
    王五已经起跑...当前时间:1548768698637
    李四已经起跑...当前时间:1548768698637

      执行分析:

      三个运动员每个人是一个线程,执行比赛这一个动作。准备工作和起跑是比赛动作的两个部分,其中准备工作耗时不同,起跑动作又需要所有运动员都准备完毕才可以进行。线程启动后,每个运动员执行自身的准备工作,然后阻塞等待其余所有线程执行完准备工作(执行完 await 前序动作),再同时执行各自线程的剩余工作(起跑)。

    图1 CyclicBarrier 执行过程分析

    三、两者区别

    1、CountDownLatch 不可重置,无法重用;CyclicBarrier 可以重置,允许重复使用。

    2、CountDownLatch 等待对象是一个线程等待多个线程执行完毕后,再自身执行,而 CyclicBarrier 是多个线程之间相互等待,等所有线程执行到统一状态时,再同时执行后续动作。   

  • 相关阅读:
    英语发音-自然拼读法
    最小二乘法
    BZOJ 1650 [Usaco2006 Dec]River Hopscotch 跳石子
    洛谷 1803 凌乱的yyy
    【模板】矩阵加速(数列)
    【模板】矩阵快速幂
    洛谷 4246 BZOJ 1018 [SHOI2008]堵塞的交通
    洛谷 1276 校门外的树(增强版)
    BZOJ 1468 Tree 【模板】树上点分治
    洛谷 1501 [国家集训队]Tree II BZOJ 2631 Tree
  • 原文地址:https://www.cnblogs.com/hanganglin/p/10335951.html
Copyright © 2020-2023  润新知