Java并发30:CountDownLatch(上)--基本方法学习

news/2024/7/16 5:02:32

[超级链接:Java并发学习系列-绪论]


本章主要对CountDownLatch的基本方法进行学习。

有关CountDownLatch的应用实例详见下一章:《Java并发:31》

1.CountDownLatch简介

CountDownLatch,是JDK1.5java.util.concurrent并发包中提供的一个并发工具类。

所谓CountDown倒计时 的意思,所谓Latch门闩 的意思。

所以综合起来,CountDownLatch指的就是 倒计时门闩,虽然这个叫法很奇怪,但是确能很好地表示它的作用。

其作用在JDK注释中是这样描述的:

A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.

简单来说,CountDownLatch就是一种同步辅助工具类,这个工具类实现的效果是:

让一个或多个线程持续等待,直到其他多线程执行的一组操作全部完成以后,这些等待的线程才会继续执行。

2.CountDownLatch原理浅谈

下面简单介绍一些CountDownLatch的实现原理。

引用[July 18, 2013 by Lokesh Gupta]的一段话和图:

CountDownLatch是通过一个计数器来实现的,计数器的初始值为线程的数量。
每当一个线程完成了自己的任务后,计数器的值就会减1。
当计数器值到达0时,它表示所有的线程已经完成了任务,然后在等待的线程就可以恢复执行任务。

这里写图片描述

3.CountDownLatch基本方法

CountDownLatch的主要方法很简单,如下:

  • getCount():获取当前count的值。
  • wait():让当前线程在此CountDownLatch对象上等待,可以中断。与notify()、notifyAll()方法对应。
  • await():让当前线程等待此CountDownLatch对象的count变为0,可以中断
  • await(timeout,TimeUnit):让当前线程等待此CountDownLatch对象的count变为0,可以超时、可以中断
  • countDown():使此CountDownLatch对象的count值减1(无论执行多少次,count最小值为0)。

注意:

  • wait()是从Object类继承来的,关于它的用法,请参加《Java并发07》,这里不再赘述。
  • 无论执行多少次countDown(),count最小值为0,不会变成负数。

4.基本方法练习

场景说明:

  • 练习目的:熟悉await():await(timeout,TimeUnit):countDown():的基本用法。
  • 共计编写5个线程:
  • thread-0 : 等待方法-await(),终止原因-latch.count=0
  • thread-1 : 等待方法-await(),终止原因-thread.interrupt()
  • thread-2 : 等待方法-await(timeout,TimeUnit),终止原因- await timeout
  • thread-3 : 等待方法-await(timeout,TimeUnit),终止原因- thread.interrupt()
  • thread-4 : 等待方法-await(timeout,TimeUnit),终止原因- latch.count=0

实例代码:

 //await()/await(timeout,TimeUnit) 与countDown()
/**
 *   线程          等待方法               终止原因
 * ------------------------------------------------
 * thread-0     await()                 count=0
 * thread-1     await()                 interrupted
 * ------------------------------------------------
 * thread-2     await(timeout,TimeUnit)    timeout
 * thread-3     await(timeout,TimeUnit)    interrupted
 * thread-4     await(timeout,TimeUnit)    count=0
 */
System.out.println();
CountDownLatch latch = new CountDownLatch(num);
//await() 直至latch 的count = 0
new Thread(() -> {
    LOGGER.info(Thread.currentThread().getName() + "(await0) is awaiting....");
    try {
        latch.await();
        LOGGER.info(Thread.currentThread().getName() + "(await0) is terminated because the latch's count is zero.");
    } catch (InterruptedException e) {
        LOGGER.info(Thread.currentThread().getName() + "(await0) is interrupted.");
        //e.printStackTrace();
    }
}).start();
//await() 被中断
Thread thread = new Thread(() -> {
    LOGGER.info(Thread.currentThread().getName() + "(await1) is awaiting....");
    try {
        latch.await();
        LOGGER.info(Thread.currentThread().getName() + "(await1) is terminated because the latch's count is zero.");
    } catch (InterruptedException e) {
        LOGGER.info(Thread.currentThread().getName() + "(await1) is terminated because it is interrupted.");
        //e.printStackTrace();
    }
});
thread.start();

//await(timeout,TimeUnit)
//await(timeout,TimeUnit) timeout
new Thread(() -> {
    LOGGER.info(Thread.currentThread().getName() + "(await2) is awaiting....");
    try {
        //等待2秒
        boolean result = latch.await(1, TimeUnit.SECONDS);
        //如果等到了count=0,则返回true,并停止等待
        if (result) {//如果返回结果为true,表示在等待时间耗尽之前等到了count=0
            LOGGER.info(Thread.currentThread().getName() + "(await2) is terminated because the latch's count is zero.");
        } else {//如果返回结果为false,表示等待时间耗尽,也没有等到count=0
            LOGGER.info(Thread.currentThread().getName() + "(await2) is terminated because the the waiting time is timeout.");
        }
    } catch (InterruptedException e) {
        LOGGER.info(Thread.currentThread().getName() + "(await2) is terminated because it is interrupted.");
        //e.printStackTrace();
    }
}).start();
//await(timeout,TimeUnit)

Thread thread1 = new Thread(() -> {
    LOGGER.info(Thread.currentThread().getName() + "(await3) is awaiting....");
    try {
        //等待3秒
        boolean result = latch.await(5, TimeUnit.SECONDS);
        //如果等到了count=0,则返回true,并停止等待
        if (result) {//如果返回结果为true,表示在等待时间耗尽之前等到了count=0
            LOGGER.info(Thread.currentThread().getName() + "(await3) is terminated because the latch's count is zero.");
        } else {//如果返回结果为false,表示等待时间耗尽,也没有等到count=0
            LOGGER.info(Thread.currentThread().getName() + "(await3) is terminated because the the waiting time is timeout.");
        }
    } catch (InterruptedException e) {
        LOGGER.info(Thread.currentThread().getName() + "(await3) is terminated because it is interrupted.");
        //e.printStackTrace();
    }
});
thread1.start();
//await(timeout,TimeUnit) count=0
new Thread(() -> {
    LOGGER.info(Thread.currentThread().getName() + "(await4) is awaiting....");
    try {
        //等待3秒
        boolean result = latch.await(5, TimeUnit.SECONDS);
        //如果等到了count=0,则返回true,并停止等待
        if (result) {//如果返回结果为true,表示在等待时间耗尽之前等到了count=0
            LOGGER.info(Thread.currentThread().getName() + "(await4) is terminated because the latch's count is zero.");
        } else {//如果返回结果为false,表示等待时间耗尽,也没有等到count=0
            LOGGER.info(Thread.currentThread().getName() + "(await4) is terminated because the the waiting time is timeout.");
        }
    } catch (InterruptedException e) {
        LOGGER.info(Thread.currentThread().getName() + "(await4) is interrupted.");
        //e.printStackTrace();
    }
}).start();
Thread.sleep(500);
System.out.println();
//等待4秒
Thread.sleep(2000);
System.out.println();
//中断
thread.interrupt();
thread1.interrupt();
Thread.sleep(1000);
System.out.println();
//进行自减,直到count=0
while (latch.getCount() > 0) {
    //LOGGER.info(Thread.currentThread().getName() + " latch.countDown , count = " + latch.getCount());
    latch.countDown();
}

运行结果:

2018-03-31 22:08:56 INFO  CountDownLatchBasic:56 - Thread-0(await0) is awaiting....
2018-03-31 22:08:56 INFO  CountDownLatchBasic:117 - Thread-4(await4) is awaiting....
2018-03-31 22:08:56 INFO  CountDownLatchBasic:99 - Thread-3(await3) is awaiting....
2018-03-31 22:08:56 INFO  CountDownLatchBasic:81 - Thread-2(await2) is awaiting....
2018-03-31 22:08:56 INFO  CountDownLatchBasic:67 - Thread-1(await1) is awaiting....

2018-03-31 22:08:57 INFO  CountDownLatchBasic:89 - Thread-2(await2) is terminated because the the waiting time is timeout.

2018-03-31 22:08:58 INFO  CountDownLatchBasic:110 - Thread-3(await3) is terminated because it is interrupted.
2018-03-31 22:08:58 INFO  CountDownLatchBasic:72 - Thread-1(await1) is terminated because it is interrupted.

2018-03-31 22:08:59 INFO  CountDownLatchBasic:59 - Thread-0(await0) is terminated because the latch's count is zero.
2018-03-31 22:08:59 INFO  CountDownLatchBasic:123 - Thread-4(await4) is terminated because the latch's count is zero.

通过分析执行结果,发现每个线程的终止方式都如预料的那样。

5.重点总结

CountDownLatch的重点方法进行总结:

  • await():等待count减少至0,或者被中断
  • await(timeout,TimeUnit):等待count减少至0,或者超时,或者被中断
  • countDown():count值减1。

http://www.niftyadmin.cn/n/2815622.html

相关文章

Java并发31:CountDownLatch(下)--两种应用场景

Java并发30:CountDownLatch(上)–基本方法学习 [超级链接:Java并发学习系列-绪论] 本章主要对CountDownLatch的两种应用场景进行学习。 有关CountDownLatch的基本方法详见上一章:《 Java并发30》 1.用法概述 本人所知的CountDownLatch的用法主要有以…

数据库开发被正式官宣成为DevOps的一部分?

相信很多人都听过“Accelerate State of DevOps Report”,今年已经是这个报告的第五年了,其调查了30000多名专业人士,其始终表明了更高的软件交付绩效可以带来的强大业务成果。2018年多的Accelerate State of DevOps Report中有一个很独特的见…

Java并发32:CyclicBarrier的基本方法和应用场景实例

[超级链接:Java并发学习系列-绪论] 本章主要对CyclicBarrier进行学习。 1.CyclicBarrier简介 CyclicBarrier,是JDK1.5的java.util.concurrent并发包中提供的一个并发工具类。 所谓Cyclic即 循环 的意思,所谓Barrier即 屏障 的意思。 所以…

[译] EthList:众包维护的以太坊阅读清单

原文地址:EthList: The Crowdsourced Ethereum Reading List原文作者:Scanate译文出自:掘金翻译计划 — 区块链分舵本文永久链接:github.com/xitu/blockc…译者:StellaBauhinia校对者:davelet发现了一个很棒…

Java并发33:Semaphore基本方法与应用场景实例

[超级链接:Java并发学习系列-绪论] 本章主要对Semaphore进行学习。 1.Semaphore简介 Semaphore,是JDK1.5的java.util.concurrent并发包中提供的一个并发工具类。 所谓Semaphore即 信号量 的意思。 这个叫法并不能很好地表示它的作用,更形…

通过Canal保证某网站的Redis与MySql的数据自动同步

前置文章: 某网站Redis与MySql同步方案分析 使用Canal的主要目的:让自动同步代替部分手动同步,降低开发人员工作量,避免部分数据一致性问题。 本文主要讲解如何配置Canal,以保证某网站的Redis与MySql的数据自动同步。…

C# 委托简介

一、简介 委托是一种类型,由关键字delegate声明。确切的说,委托是一种可用于封装命名或者匿名方法的引用类型。 它类似于 C 中的函数指针,而且是类型安全和可靠的。 委托类型的声明与方法签名相似,有一个返回值和任意数目任意类型…

VMware安装Ubuntu记录

1.下载并安装VMware VMware-workstation-full-14.1.1.28517.exe2.下载并安装Ubuntu镜像 ubuntu-16.04.3-desktop-amd64.iso3.安装WMware tools解决全屏显示问题 http://www.jb51.net/os/Ubuntu/356462.html 4.安装输入法 https://blog.csdn.net/u011795345/article/detail…