JUC包下的线程协作计数CountDownLatch及CyclicBarrier

CountDownLatch

概述

用来进行线程同步协作,等待所有线程完成倒计时。

其中构造参数用来初始化等待计数值,await() 用来等待计数归零,countDown() 用来让计数减一

CountDownLatch不能重用,只能减不能加

public static void main(String[] args) throws InterruptedException {
    CountDownLatch latch = new CountDownLatch(3);
    new Thread(() -> {
        log.debug("begin...");
        sleep(1);
        latch.countDown();
        log.debug("end...{}", latch.getCount());
    }).start();
    new Thread(() -> {
        log.debug("begin...");
        sleep(2);
        latch.countDown();
        log.debug("end...{}", latch.getCount());
    }).start();
    new Thread(() -> {
        log.debug("begin...");
        sleep(1.5);
        latch.countDown();
        log.debug("end...{}", latch.getCount());
    }).start();
    log.debug("waiting...");
    latch.await();
    log.debug("wait end...");
}

输出

18:44:00.778 c.TestCountDownLatch [main] - waiting...
18:44:00.778 c.TestCountDownLatch [Thread-2] - begin...
18:44:00.778 c.TestCountDownLatch [Thread-0] - begin...
18:44:00.778 c.TestCountDownLatch [Thread-1] - begin...
18:44:01.782 c.TestCountDownLatch [Thread-0] - end...2
18:44:02.283 c.TestCountDownLatch [Thread-2] - end...1
18:44:02.782 c.TestCountDownLatch [Thread-1] - end...0
18:44:02.782 c.TestCountDownLatch [main] - wait end... 

可以配合线程池使用,改进如下

public static void main(String[] args) throws InterruptedException {
    CountDownLatch latch = new CountDownLatch(3);
    ExecutorService service = Executors.newFixedThreadPool(4);
    service.submit(() -> {
        log.debug("begin...");
        sleep(1);
        latch.countDown();
        log.debug("end...{}", latch.getCount());
    });
    service.submit(() -> {
        log.debug("begin...");
        sleep(1.5);
        latch.countDown();
        log.debug("end...{}", latch.getCount());
    });
    service.submit(() -> {
        log.debug("begin...");
        sleep(2);
        latch.countDown();
        log.debug("end...{}", latch.getCount());
    });
    service.submit(()->{
        try {
            log.debug("waiting...");
            latch.await();
            log.debug("wait end...");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    });
}

应用

等待多线程准备完毕

AtomicInteger num = new AtomicInteger(0);
ExecutorService service = Executors.newFixedThreadPool(10, (r) -> {
    return new Thread(r, "t" + num.getAndIncrement());
});
CountDownLatch latch = new CountDownLatch(10);
String[] all = new String[10];
Random r = new Random();
for (int j = 0; j < 10; j++) {
    int x = j;
    service.submit(() -> {
        for (int i = 0; i <= 100; i++) {
            try {
                Thread.sleep(r.nextInt(100));
            } catch (InterruptedException e) {
            }
            all[x] = Thread.currentThread().getName() + "(" + (i + "%") + ")";
            System.out.print("\r" + Arrays.toString(all));
        }
        latch.countDown();
    });
}
latch.await();
System.out.println("\n游戏开始...");
service.shutdown();

CyclicBarrier

循环栅栏,用来进行线程协作,等待线程满足某个计数。构造时设置『计数个数』,每个线程执
行到某个需要“同步”的时刻调用 await() 方法进行等待,当等待的线程数满足『计数个数』时,继续执行

构造方法:

  • public CyclicBarrier(int parties)
  • public CyclicBarrier(int parties, Runnable barrierAction)

parties是参与线程的个数,每次调用await等待的线程数加一,直到达到parties所有线程继续运行。Runnable 参数则是可以选择计数值达到parties要做的任务。

在计数值达到parties之后,等待的线程数清零,可以重用。

CyclicBarrier cb = new CyclicBarrier(2); // 个数为2时才会继续执行
new Thread(()->{
    System.out.println("线程1开始.."+new Date());
    try {
        cb.await(); // 当个数不足时,等待
    } catch (InterruptedException | BrokenBarrierException e) {
        e.printStackTrace();
    }
    System.out.println("线程1继续向下运行..."+new Date());
}).start();
new Thread(()->{
    System.out.println("线程2开始.."+new Date());
    try { Thread.sleep(2000); } catch (InterruptedException e) { }
    try {
        cb.await(); // 2 秒后,线程个数够2,继续运行
    } catch (InterruptedException | BrokenBarrierException e) {
        e.printStackTrace();
    }
    System.out.println("线程2继续向下运行..."+new Date());
}).start();

原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/juc%e5%8c%85%e4%b8%8b%e7%9a%84%e7%ba%bf%e7%a8%8b%e5%8d%8f%e4%bd%9c%e8%ae%a1%e6%95%b0countdownlatch%e5%8f%8acyclicbarrier/

(0)
彭晨涛彭晨涛管理者
上一篇 2020年2月6日
下一篇 2020年2月7日

相关推荐

  • Java基础查缺补漏01

    某些点会在不远的将来深挖。 >>是逻辑右移,>>>是算术右移 JDK6 可以使用Console.readPassword从控制台中读取密码,用户输入的过程中密码是不可见的。…

    2019年11月26日
    0590
  • 网络编程之AIO

    AIO介绍 AIO是JDK1.7引入的,也称为NIO 2.0 NIO的同步非阻塞类似于轮询,让Selector去询问各个通道的状态。 而AIO则是通过Future实现真正的异步,让…

    Java 2020年2月8日
    0280
  • LinkedHashMap源码分析

    总结 总结放前面防止太长不看: LinkedHashMap继承自HashMap,为Entry额外维护了两个属性:before和after,可以按照节点的插入顺序或者访问顺序为Ent…

    Java 2020年2月19日
    0550
  • 深入理解java虚拟机第三版读书笔记11

    以下是第十一章 后端编译与优化的内容 把Class文件转换成与本地基础设施(硬件指令集、操作系统)相关的二进制机器码可以视为整个编译过程的后端。 最近几年提前编译也开始兴起,我们在…

    2020年1月27日
    0290
  • 谈一谈StringBuffer、StringBuilder及String在JDK9中的变化

    本文参考资源: JAVA9 String新特性,说说你不知道的东西Java人在江湖-CSDN博客 StringBuffer和StringBuilder的区别 这里谈的是JDK8中S…

    2020年4月9日
    0350
  • Java多线程共享模型之管程

    Monitor(锁) Monitor被翻译为监视器或管程。 Monitor是重量级锁的实现,是向操作系统申请的。 Monitor的结构:WaitSet、EntryList、Owne…

    2020年2月2日
    0930
  • Java基础查缺补漏05

    继续我的复习刷题 可以有和类名同名的函数 题目: JAVA中,下列语句哪一个正确() A. class中的constructor不可省略B. constructor必须与class…

    Java 2020年5月29日
    0140
  • Java字节码实例探究

    深入理解java虚拟机第三版读书笔记06中介绍了class文件结构,这里我们动手实践,编译一个类查看一下它的字节码。 java源码: public class Main { pri…

    2020年1月23日
    0220
  • 详解Java中的四种引用及其应用

    本文参考资源: 深入理解Java中的引用(一)——Reference - 简书 深入理解Java中的引用(二)——强软弱虚引用 - 简书 深入理解Java中的引用(三)——Dire…

    2020年2月14日
    0190
  • PriorityQueue源码分析

    总结 总结放前面防止太长不看: PriorityQueue是个最小堆,如果要改变排序顺序只能重写比较器传入构造方法。 内部元素要么实现Comparable接口,要么传入比较器进行比…

    Java 2020年2月10日
    0260

发表回复

登录后才能评论