并发之CountDownLatch

CountDownLatch,谓之倒计数器。这个工具通常用来控制线程等待,一个或多个线程通过await()方法,等待同组其他线程完成,整个过程是阻塞的。同组线程都完成后,才会继续往后执行。通俗地说,万事俱备再行动的意思。API中的描述如下:

用给定的计数 初始化 CountDownLatch。由于调用了 countDown() 方法,所以在当前计数到达零之前,await 方法会一直受阻塞。之后,会释放所有等待的线程,await 的所有后续调用都将立即返回。这种现象只出现一次——计数无法被重置。如果需要重置计数,请考虑使用 CyclicBarrier。

我们以图示意:


看图说话

我们看下构造方法:

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

可以看到,依然是采用了继承了AQSSync,它依然是内部类。
锁的释放和等待分别为countdown()await()方法,我们看下源码:

    public void await() throws InterruptedException {
        /**调用sync的共享锁,内部自旋通过getState()获取计数器的状态值,
         *只有等 于零时才会cancel
         */
        sync.acquireSharedInterruptibly(1);
    }
    public void countDown() {
        sync.releaseShared(1);//将当前线程的状态归零
    }

我们用等队友打球作为示例,演示下用法:

public class CountDownLatchTest {
    static CountDownLatch countDownLatch ;
    final static Random random = new Random();

    static class Teammate implements Runnable {
        String name;

        public Teammate(String name) {
            this.name = name;
        }

        @Override
        public void run() {
          int time = random.nextInt(10)+1;
            try {
                System.out.println(this.name+" 还有 "+time+" 分钟到达!");
                Thread.sleep(time*1000);
                System.out.println(this.name+" 到了");
                countDownLatch.countDown();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) throws InterruptedException {
        countDownLatch = new CountDownLatch(8);
        for (int i = 1; i < 9; i++) {
            new Thread(new Teammate("player" + i)).start();
        }
        countDownLatch.await();//只有8个队友都到了才会往下执行
        System.out.println("人到齐了,4V4开始吧");
    }
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容