java并发中CountDownLatch的使用

在java并发中,控制共享变量的访问非常重要,有时候我们也想控制并发线程的执行顺序,比如:等待所有线程都执行完毕之后再执行另外的线程,或者等所有线程都准备好了才开始所有线程的执行等。

这个时候我们就可以使用到CountDownLatch。

简单点讲,CountDownLatch存有一个放在QueuedSynchronizer中的计数器。当调用countdown() 方法时,该计数器将会减一。然后再调用await()来等待计数器归零。


private static final class Sync extends AbstractQueuedSynchronizer {
...
} private final Sync sync; public void countDown() {
sync.releaseShared(1);
}
    public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
} public boolean await(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}

下面我们举两个使用的例子:

主线程等待子线程全都结束之后再开始运行

这里我们定义子线程类,在子线程类里面,我们传入一个CountDownLatch用来计数,然后在子线程结束之前,调用该CountDownLatch的countDown方法。最后在主线程中调用await()方法来等待子线程结束执行。

@Slf4j
public class MainThreadWaitUsage implements Runnable { private List<String> outputScraper;
private CountDownLatch countDownLatch; public MainThreadWaitUsage(List<String> outputScraper, CountDownLatch countDownLatch) {
this.outputScraper = outputScraper;
this.countDownLatch = countDownLatch;
} @Override
public void run() {
outputScraper.add("Counted down");
countDownLatch.countDown();
}
}

看下怎么调用:

    @Test
public void testCountDownLatch()
throws InterruptedException { List<String> outputScraper = Collections.synchronizedList(new ArrayList<>());
CountDownLatch countDownLatch = new CountDownLatch(5);
List<Thread> workers = Stream
.generate(() -> new Thread(new MainThreadWaitUsage(outputScraper, countDownLatch)))
.limit(5)
.collect(toList()); workers.forEach(Thread::start);
countDownLatch.await();
outputScraper.add("Latch released");
log.info(outputScraper.toString()); }

执行结果如下:

07:37:27.388 [main] INFO MainThreadWaitUsageTest - [Counted down, Counted down, Counted down, Counted down, Counted down, Latch released]

等待所有线程都准备好再一起执行

上面的例子中,我们是主线程等待子线程,那么在这个例子中,我们将会看看怎么子线程一起等待到准备好的状态,再一起执行。

思路也很简单,在子线程开始之后,将等待的子线程计数器减一,在主线程中await该计数器,等计数器归零之后,主线程再通知子线程运行。

public class ThreadWaitThreadUsage implements Runnable {

    private List<String> outputScraper;
private CountDownLatch readyThreadCounter;
private CountDownLatch callingThreadBlocker;
private CountDownLatch completedThreadCounter; public ThreadWaitThreadUsage(
List<String> outputScraper,
CountDownLatch readyThreadCounter,
CountDownLatch callingThreadBlocker,
CountDownLatch completedThreadCounter) { this.outputScraper = outputScraper;
this.readyThreadCounter = readyThreadCounter;
this.callingThreadBlocker = callingThreadBlocker;
this.completedThreadCounter = completedThreadCounter;
} @Override
public void run() {
readyThreadCounter.countDown();
try {
callingThreadBlocker.await();
outputScraper.add("Counted down");
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
completedThreadCounter.countDown();
}
}
}

看下怎么调用:

    @Test
public void testCountDownLatch()
throws InterruptedException { List<String> outputScraper = Collections.synchronizedList(new ArrayList<>());
CountDownLatch readyThreadCounter = new CountDownLatch(5);
CountDownLatch callingThreadBlocker = new CountDownLatch(1);
CountDownLatch completedThreadCounter = new CountDownLatch(5);
List<Thread> workers = Stream
.generate(() -> new Thread(new ThreadWaitThreadUsage(
outputScraper, readyThreadCounter, callingThreadBlocker, completedThreadCounter)))
.limit(5)
.collect(toList()); workers.forEach(Thread::start);
readyThreadCounter.await();
outputScraper.add("Workers ready");
callingThreadBlocker.countDown();
completedThreadCounter.await();
outputScraper.add("Workers complete"); log.info(outputScraper.toString()); }

输出结果如下:

07:41:47.861 [main] INFO ThreadWaitThreadUsageTest - [Workers ready, Counted down, Counted down, Counted down, Counted down, Counted down, Workers complete]

停止CountdownLatch的await

如果我们调用await()方法,该方法将会等待一直到count=0才结束。但是如果在线程执行过程中出现了异常,可能导致countdown方法执行不了。那么await()方法可能会出现无限等待的情况。

这个时候我们可以使用:

    public boolean await(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}

本文的例子可以参考https://github.com/ddean2009/learn-java-concurrency/tree/master/CountDownLatch

更多教程请参考 flydean的博客

java并发中CountDownLatch的使用的更多相关文章

  1. 深入浅出Java并发中的CountDownLatch

      1. CountDownLatch 正如每个Java文档所描述的那样,CountDownLatch是一个同步工具类,它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行.在Java并发中 ...

  2. java并发初探CountDownLatch

    java并发初探CountDownLatch CountDownLatch是同步工具类能够允许一个或者多个线程等待直到其他线程完成操作. 当前前程A调用CountDownLatch的await方法进入 ...

  3. java并发中ExecutorService的使用

    文章目录 创建ExecutorService 为ExecutorService分配Tasks 关闭ExecutorService Future ScheduledExecutorService Exe ...

  4. java并发中的Synchronized关键词

    文章目录 为什么要同步 Synchronized关键词 Synchronized Instance Methods Synchronized Static Methods Synchronized B ...

  5. JAVA并发,CountDownLatch使用

    该文章转自:http://www.itzhai.com/the-introduction-and-use-of-a-countdownlatch.html CountDownLatch 1.类介绍 一 ...

  6. Java并发——结合CountDownLatch源码、Semaphore源码及ReentrantLock源码来看AQS原理

    前言: 如果说J.U.C包下的核心是什么?那我想答案只有一个就是AQS.那么AQS是什么呢?接下来让我们一起揭开AQS的神秘面纱 AQS是什么? AQS是AbstractQueuedSynchroni ...

  7. Java并发中的CopyOnWrite容器

    Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改, ...

  8. Java并发编程-CountDownLatch

    基于AQS的前世今生,来学习并发工具类CountDownLatch.本文将从CountDownLatch的应用场景.源码原理解析来学习这个并发工具类. 1. 应用场景 CountDownLatch是并 ...

  9. 一起来看看java并发中volatile关键字的神奇之处

    并发编程中的三个概念: 1.原子性 在Java中,对基本数据类型的变量的读取和赋值操作是原子性操作,即这些操作是不可被中断的,要么执行,要么不执行. 2.可见性 对于可见性,Java提供了volati ...

随机推荐

  1. 机器学习——详解KD-Tree原理

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是机器学习的第15篇文章,之前的文章当中讲了Kmeans的相关优化,还讲了大名鼎鼎的EM算法.有些小伙伴表示喜欢看这些硬核的,于是今天上 ...

  2. 通过pycharm使用git和github的步骤(图文详解)

    一.在Pycharm工具中配置集成Git和GitHub.1.集成Git. 打开Pycharm,  点击File-->Settins-->Version Control-->Git 然 ...

  3. vue按需引入/全局引入echarts

    npm install echarts -S 1.按需引入 新建echarts.js公共引入 // 文件路径 @/lib/echarts.js 自行配置 // 加载echarts,注意引入文件的路径 ...

  4. CTF中常用的php伪协议利用

    1.file:// 作用: 用于访问文件(绝对路径.相对路径.网络路径) 示例: http://www.xx.com?file=file:///etc/passsword 2.php:// 作用:访问 ...

  5. PTA数据结构与算法题目集(中文) 7-26

    PTA数据结构与算法题目集(中文)  7-26 7-26 Windows消息队列 (25 分)   消息队列是Windows系统的基础.对于每个进程,系统维护一个消息队列.如果在进程中有特定事件发生, ...

  6. mac 升级到mavericks 安装php扩展现问题

    mac 升级到mavericks 安装php扩展现以下问题 grep: /usr/include/php/main/php.h: No such file or directory grep: /us ...

  7. Linux服务器架设篇,DHCP服务器的搭建

    学习之前,我们首先来看一个案例: 假如你是一个学校的网络管理老师,需要为教室的70多台电脑配置好网络你会怎么办? 一台一台的给他们配置? 在这里我特别欣赏鸟哥的一句话--"当管理员最大的幸福 ...

  8. 如何在云开发静态托管中使用Hugo

    如何在云开发静态托管中使用Hugo 介绍 hugo是一个用Go编写的静态站点生成器,由于具有丰富的主题资源和有比较丰富的主题资源和较好的生成速度. 云开发(CloudBase)是一款云端一体化的产品方 ...

  9. 使用Network Emulator Toolkit工具模拟网络丢包测试(上)

    弱网络测试包括延时和丢包二种场景下应用的功能是否正常: 网络延时测试使用Fiddler工具控制上下行数据传输延时时间来模拟网络延时场景: 网络丢包测试使用Network Emulator Toolki ...

  10. [总结]RMQ问题&ST算法

    目录 一.ST算法 二.ST算法の具体实现 1. 初始化 2. 求出ST表 3. 询问 三.例题 例1:P3865 [模板]ST表 例2:P2880 [USACO07JAN]平衡的阵容Balanced ...