zoukankan      html  css  js  c++  java
  • CountDownLatch和CycliBarrier介绍

    一、CountDownLatch

      它被用来同步一个或多个任务,强制他们等待其他任务完成,这就是闭锁。

    public CountDownLatch(int count) {
            if (count < 0) throw new IllegalArgumentException("count < 0");
            this.sync = new Sync(count);
        }

      类中只有一个构造函数,一个int类型的参数count,代表计数器。这个计数器的初始值是线程的数量,每当一个线程结束,count-1,当count==0 时,所有线程执行完毕,在闭锁上等待的线程就可以执行了。

    类中还包含了三个公共方法:

    public void await()
    public boolean await(long timeout, TimeUnit unit)
    public void countDown()

      当每个任务完成时,都会调用countDown()方法。而等待问题被解决的任务在这个锁存器上调用await()方法,这个任务就相当于被挂起了直到 timeout 或 计数器为0

    public class CountDownLatchDemo {
        static final int SIZE = 5;
    
        public static void main(String[] args) {
            ThreadPoolExecutor pool = new ThreadPoolExecutor(5, 10, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(5));
            CountDownLatch countDownLatch = new CountDownLatch(SIZE);
            pool.execute(new WaitTask(countDownLatch));
            for (int i = 0; i < SIZE; i++) {
                pool.execute(new TaskNow(countDownLatch));
            }
        }
    
    }
    
    class TaskNow implements Runnable {
        private final CountDownLatch countDownLatch;
    
        TaskNow(CountDownLatch countDownLatch) {
            this.countDownLatch = countDownLatch;
        }
    
        @Override
        public void run() {
            try {
                TimeUnit.MILLISECONDS.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("我没完事你别想跑");
            //调用countDown()的方法会减少count次数直到为0,调用await的任务才能进行
            countDownLatch.countDown();
        }
    }
    
    class WaitTask implements Runnable {
        private final CountDownLatch countDownLatch;
    
        WaitTask(CountDownLatch countDownLatch) {
            this.countDownLatch = countDownLatch;
        }
    
        @Override
        public void run() {
            try {
                //调用await的任务会被挂起
                countDownLatch.await();
                System.out.println("终于轮到我了");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    结果:

      我没完事你别想跑
      我没完事你别想跑
      我没完事你别想跑
      我没完事你别想跑
      我没完事你别想跑
      终于轮到我了

    二、CylicBarrier

      栅栏类似于闭锁,只是要等到所有线程都到达栅栏,才能进行接下来的动作,在没到达栅栏之前先到的要等待。

    构造方法

    共有两个构造方法:

    public CyclicBarrier(int parties, Runnable barrierAction) {
            if (parties <= 0) throw new IllegalArgumentException();
            this.parties = parties;
            this.count = parties;
            this.barrierCommand = barrierAction;
        }
    public CyclicBarrier(int parties) {
            this(parties, null);
        }

    CyclicBarrier默认的构造方法是CyclicBarrier(int parties),其参数表示屏障拦截的线程数量,每个线程使用await()方法告诉CyclicBarrier我已经到达了屏障,然后当前线程被阻塞。

    CyclicBarrier的另一个构造函数CyclicBarrier(int parties, Runnable barrierAction),用于线程到达屏障时,优先执行barrierAction,方便处理更复杂的业务场景。

    await()方法

      线程调用await()方法表示已经到达同步点,然后当前线程被阻塞。直到parties个参与线程调用了await()方法,CyclicBarrier同样提供带超时时间的await和不带超时时间的await方法:

    public int await() throws InterruptedException, BrokenBarrierException {
        try {
            return dowait(false, 0L);
        } catch (TimeoutException toe) {
            throw new Error(toe); // cannot happen
        }
    }
    public int await(long timeout, TimeUnit unit)throws InterruptedException,BrokenBarrierException,TimeoutException{...}

      可以看到await方法调用了dowait()方法,dowait()方法是核心方法其内容是:如果这个线程不是最后一个到达的线程那么进行等待直到:

    • 最后一个线程到达,即index == 0
    • 某个参与线程等待超时
    • 某个参与线程被中断
    • 调用了CyclicBarrier的reset()方法。该方法会将屏障重置为初始状态

    案例

    public class CycliBarrierDemo {
    
    
        public static void main(String[] args) {
            int threadCount = 3;
            CyclicBarrier cyclicBarrier = new CyclicBarrier(threadCount);
            ThreadPoolExecutor pool = new ThreadPoolExecutor(5, 10, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1));
            for (int i = 0; i < threadCount; i++) {
                pool.execute(new Horse(cyclicBarrier, i));
            }
        }
    }
    
    class Horse implements Runnable {
        private CyclicBarrier cyclicBarrier;
        private int num;
    
        public Horse(CyclicBarrier cyclicBarrier, int num) {
            this.cyclicBarrier = cyclicBarrier;
            this.num = num;
        }
    
        @Override
        public void run() {
            System.out.println("马匹:" + num + "到了");
            try {
                cyclicBarrier.await();
                System.out.println("马匹:" + num + "在等待");
                TimeUnit.MILLISECONDS.sleep(2000);
            } catch (InterruptedException | BrokenBarrierException e) {
                e.printStackTrace();
            }
            System.out.println("马匹到齐");
        }
    }


    结果:

      马匹:0到了
      马匹:2到了
      马匹:1到了
      马匹:1在等待
      马匹:0在等待
      马匹:2在等待
      马匹到齐
      马匹到齐
      马匹到齐

     

      

  • 相关阅读:
    《Django By Example》第十二章(终章) 中文 翻译 (个人学习,渣翻)
    《Django By Example》第十一章 中文 翻译 (个人学习,渣翻)
    《Django By Example》第十章 中文 翻译 (个人学习,渣翻)
    《Django By Example》第九章 中文 翻译 (个人学习,渣翻)
    《Django By Example》第八章 中文 翻译 (个人学习,渣翻)
    《Django By Example》第五章 中文 翻译 (个人学习,渣翻)
    我的superui开源后台bootstrap开发框架
    LayoutInflater 总结
    Android屏幕分辨率概念(dp、dip、dpi、sp、px)
    android studio安装问题
  • 原文地址:https://www.cnblogs.com/xcgShare/p/11765231.html
Copyright © 2011-2022 走看看