倒计数锁存器(CountDown Latch)和 CyclicBarrier(同步屏障)

倒计数锁存器(CountDown Latch)是异常性障碍,允许一个或多个线程等待一个或者多个其他线程来做某些事情。

 public  static long time(Executor executor,int concurrency,final Runnable action)throws InterruptedException{
        //CountDownLatch 构造器参数代表 只有调用countDown()方法达到这个int值的时候,才能继续(所以多线程的情况下可以在此阻塞)
        final CountDownLatch ready=new CountDownLatch(concurrency);
        final CountDownLatch start=new CountDownLatch(1);
        final CountDownLatch done=new CountDownLatch(concurrency);
        for (int i=0;i<concurrency;i++){
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    ready.countDown();//准备好了一个就++1
                    try{
                        start.await();//等待所有for循环跑完 主线程执行countDown的时候才能继续走
                        action.run();
                    }catch (InterruptedException ex){
                        Thread.currentThread().interrupt();
                    }finally{
                        done.countDown();//线程执行完了才能++
                    }
                }
            });
        }
        ready.await();
        long startNanos=System.nanoTime();
        start.countDown();
        done.await();//阻塞等待异步线程的countDown()调用次数达到阀值
        return  System.nanoTime()-startNanos;
    }

对于间歇式的定时,始终应该优先使用System.nanoTime()而不是System.currentTimeMills,前者更加准确更加精确并且不受系统的实时时钟的调整影响。

三个CountdownLatch也可以用CyclicBarrier(同步屏障)代替。

 public static long time1(Executor executor, int concurrency, final Runnable action) {
        CyclicBarrier cyclicBarrier = new CyclicBarrier(concurrency);
        long startNanos = System.nanoTime();
        for (int i = 0; i < concurrency; i++) {
            executor.execute(new Runnable() {
                @Override
                public void run() {
                    try {
                        action.run();
                    } finally {
                        try {
                            cyclicBarrier.await();
                        } catch (BrokenBarrierException ex) {

                        } catch (InterruptedException ex) {

                        }
                    }
                }
            });
        }
        return System.nanoTime() - startNanos;
    }

CountDownLatch的计数器只能使用一次。而CyclicBarrier的计数器可以使用reset() 方法重置。所以CyclicBarrier能处理更为复杂的业务场景,比如如果计算发生错误,可以重置计数器,并让线程们重新执行一次。
CyclicBarrier还提供其他有用的方法,比如getNumberWaiting方法可以获得CyclicBarrier阻塞的线程数量。isBroken方法用来知道阻塞的线程是否被中断。

总的来说就是可以同步等待所有异步任务完成后进行汇总操作。

原文地址:https://www.cnblogs.com/ylsforever/p/8434863.html