CountDownLatch是什么?

CountDownLatch是JDK1.5之后提供的一个同步工具,在并发包下面,它可以让一个或多个线程等待,一直等到其他线程中执行完成一组操作。实现功能和java多线程中的join() 方法很像;想要详细了解join方法可以看我另一篇文章: java多线程join()方法的作用和实现原理

CountDownLatch有哪些常用方法

CountDownLatch在调用构造方法初始化时,需要指定用给定一个整数作为计数器;这个计数器用来阻塞await方法;

  • countDown方法 : 计数器会被减1,调用此方法不会阻塞
  • await方法           : 如果计数器大于0时,线程会被阻塞,一直到计数器被countDown方法减到0时,线程才会继续执行。计数器是无法重置的,当计数器被减到0时,调用await方法都会直接返回。从而解除阻塞状态执行await方法后面的代码;

应用场景

说明白了用法,那么这个同步工具能用在哪些场景呢?假设我们有以下的场景:

比如有三个人小红、小李、小王, 三个人相约一起去酒店吃饭,菜已经点好了, 三个人从不同的地方出发,只有三个人都到了酒店之后才会开始上菜;那么这三个人就分别代表三个线程,这三个线程执行完之后才会执行 “上菜” 的代码逻辑;这种场景下就可以使用CountDownLatch实现

上代码  ConutDownLatchDemo.java

package com.Lock;import java.util.concurrent.CountDownLatch;/***  使用CountDownLatch同步器实现多线程等待*  比如有三个人小红、小李、小王, 三个人相约一起去酒店吃饭,菜已经点好了, 三个人从不同的地方出发,只有三个人都到了酒店之后才会开始上菜;那么这三个人就分别代表三个线程,这三个线程执行完之后才会执行 “上菜” 的代码逻辑,**/
public class ConutDownLatchDemo implements  Runnable{CountDownLatch latch ;public ConutDownLatchDemo (CountDownLatch latch){this.latch = latch;}@Overridepublic void run() {System.out.println(Thread.currentThread().getName()+"开始出发了");try {Thread.sleep(1000);  // 到酒店的过程中用延时1秒来代替} catch (InterruptedException e) {e.printStackTrace();}System.out.println(Thread.currentThread().getName()+"到酒店了");latch.countDown();// 计数器 - 1}
}class Hotel implements  Runnable{// 同步工具CountDownLatch latch ;public Hotel (CountDownLatch latch){this.latch = latch;}@Overridepublic void run() {System.out.println(Thread.currentThread().getName() +"正在等待大家的到来.....");try {// 如果计数器的值 > 0 ,则执行当前方法时进入阻塞,如果小于0,则放行latch.await();} catch (InterruptedException e) {e.printStackTrace();}System.out.println("人齐了,"+Thread.currentThread().getName() +"服务员开始上菜");}
}class Main1{public static void main(String[] args) throws InterruptedException {CountDownLatch latch = new CountDownLatch(3);new Thread(new ConutDownLatchDemo(latch), "小红").start();new Thread(new ConutDownLatchDemo(latch), "小王").start();new Thread(new ConutDownLatchDemo(latch), "小李").start();// 酒店线程new Thread(new Hotel(latch), "酒店").start();}
}

通过打印结果可以看到,服务员上菜之前,酒店的线程一直阻塞着,只有当三个人都到了酒店之后才会开始上菜;

其中一个线程阻塞了或者挂了怎么办?

三个人一起到饭店吃饭,如果有一个人在路上出了点事情,迟迟不能到饭店,或者说临时被老板叫去加班, 不来了,其他的人也不能一直等啊,这时候怎么办?

解决办法很简单,await() 有一个重载的方法

await(long timeout, TimeUnit unit)

比如我们设置为5秒钟,

latch.await(5, TimeUnit.SECONDS);

那么超过5秒后,不管人来没来齐,服务员都会照样上菜;

CountDownLatch的实现原理

CountDownLatch有一个内部类叫做Sync,它继承了AbstractQueuedSynchronizer类,其中维护了一个整数state,并且保证了修改state的可见性和原子性。

创建CountDownLatch实例时,也会创建一个Sync的实例,同时把计数器的值传给Sync实例,具体是这样的:

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

在 countDown方法中,只调用了Sync实例的releaseShared方法,具体是这样的:

public void countDown() {sync.releaseShared(1);
}

其中的releaseShared方法,先对计数器进行减1操作,如果减1后的计数器为0,唤醒被await方法阻塞的所有线程,具体是这样的:

public final boolean releaseShared(int arg) {if (tryReleaseShared(arg)) { //对计数器进行减一操作doReleaseShared();//如果计数器为0,唤醒被await方法阻塞的所有线程return true;}return false;
}

其中的tryReleaseShared方法,先获取当前计数器的值,如果计数器为0时,就直接返回;如果不为0时,使用CAS方法对计数器进行减1操作,具体是这样的:

protected boolean tryReleaseShared(int releases) {for (;;) {//死循环,如果CAS操作失败就会不断继续尝试。int c = getState();//获取当前计数器的值。if (c == 0)// 计数器为0时,就直接返回。return false;int nextc = c-1;if (compareAndSetState(c, nextc))// 使用CAS方法对计数器进行减1操作return nextc == 0;//如果操作成功,返回计数器是否为0}
}

await方法中,只调用了Sync实例的acquireSharedInterruptibly方法,具体是这样的:

public void await() throws InterruptedException {sync.acquireSharedInterruptibly(1);
}

其中acquireSharedInterruptibly方法,判断计数器是否为0,如果不为0则阻塞当前线程,具体是这样的:

public final void acquireSharedInterruptibly(int arg)throws InterruptedException {if (Thread.interrupted())throw new InterruptedException();if (tryAcquireShared(arg) < 0)//判断计数器是否为0doAcquireSharedInterruptibly(arg);//如果不为0则阻塞当前线程
}

其中tryAcquireShared方法,是AbstractQueuedSynchronizer中的一个模板方法,其具体实现在Sync类中,其主要是判断计数器是否为零,如果为零则返回1,如果不为零则返回-1,具体是这样的:

protected int tryAcquireShared(int acquires) {return (getState() == 0) ? 1 : -1;
}

简约而不简单的CountDownLatch相关推荐

  1. 暗黑风java战棋游戏_简约而不简单的类暗黑战棋游戏

    评测:<符石守护者>--简约而不简单 一句话总结:国产战棋游戏精品 引入了大量暗黑因素的回合制游戏,在零零散散诸多设定下,竟然呈现出一种暗黑的游戏感,不得不令人叹服. <符石守护者& ...

  2. 【Python】简约而不简单|值得收藏的Numpy小抄表(含主要语法、代码)

    Numpy是一个用python实现的科学计算的扩展程序库,包括: 1.一个强大的N维数组对象Array: 2.比较成熟的(广播)函数库: 3.用于整合C/C++和Fortran代码的工具包: 4.实用 ...

  3. 简约而不简单|值得收藏的Pandas基本操作指南

    Pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的.Pandas 纳入了大量库和一些标准的数据模型,提供了高效地操作大型数据集所需的工具.pandas提供了大量能使我们快 ...

  4. 简约而不简单|值得收藏的Numpy小抄表(含主要语法、代码)

    Numpy是一个用python实现的科学计算的扩展程序库,包括: 1.一个强大的N维数组对象Array: 2.比较成熟的(广播)函数库: 3.用于整合C/C++和Fortran代码的工具包: 4.实用 ...

  5. 程序员过关斩将--为微服务撸一个简约而不简单的配置中心

    点击上方蓝字  关注我们 毫不犹豫的说,现代高速发展的互联网造就了一批又一批的网络红人,这一批批网红又极大的催生了特定平台的一大波流量,但是留给了程序员却是一地鸡毛,无论是运维还是开发,每天都会担心服 ...

  6. 简约而不简单的 Django 新手图文教程

    来源:cizixs segmentfault.com/a/1190000008387882 本文面向:有python基础,刚接触web框架的初学者. 环境:windows7,python3.5.1,p ...

  7. Python Numpy知识 - 简约而不简单的 Numpy 小抄表(语法、代码)

    目录 前言 零.安装Numpy 一.Numpy基础 1.常用操作 2.占位符 二.数组 1.数组属性 2.拷贝 /排序 3.数组操作例程 (1)增加或减少元素 (2)组合数组 (3)分割数组 (4)数 ...

  8. 【Python】简约而不简单的Numpy小抄表(含主要语法、代码)

    Numpy是一个用python实现的科学计算的扩展程序库,包括: 1.一个强大的N维数组对象Array: 2.比较成熟的(广播)函数库: 3.用于整合C/C++和Fortran代码的工具包: 4.实用 ...

  9. 一道简约而不简单的算法题——数据流的中位数 | 附动画解析

    作者 | 程序员小吴 转载自微信公众号(ID:CXYxiaowu) 题目来源于 LeetCode 上第 295 号问题:数据流的中位数.难度级别为 Hard,目前通过率为 33.5% . 题目描述 中 ...

最新文章

  1. 马斯克再发声,称人工智能是人类文明面临的最大风险
  2. postgresql测试题_PostgreSQL练习
  3. 一个链表创建、反转、打印的C语言代码
  4. javascript与xml实例应用
  5. c# mysql sdr_C#结合数据库实现验证识别ID卡内容的方法
  6. 使用commons-fileupload-1.2.1.jar等组件实现文件上传
  7. 计算机科学文学学士,波士顿大学计算机科学.pdf
  8. mysql 1053错误,无法启动的解决方法
  9. 如何使用SQL Server数据工具中的“可见性”选项降低报告的复杂性
  10. 解决办法:java.lang.UnsatisfiedLinkError: org.opencv.core.Mat.n_eye(III)J
  11. 《女士品茶》读书笔记
  12. SVN E200030: There are unfinished transactions detected
  13. 结合分析和数值技术 Python 在基本力学应用
  14. 毛孔很大很难看该怎么处理
  15. IT视频课程集(包含各类Oracle、DB2、Linux、Mysql、Nosql、Hadoop、BI、云计算、编程开发、网络、大数据、虚拟化
  16. 人人商城提示“app被您禁用啦,可以访问lbsyun.baidu.com/apiconsole/key#”
  17. DPDKVPP关键技术文档总结
  18. mac pro M1(ARM)安装:ubuntu虚拟机(四)
  19. 入坑esp-01s 1.3寸OLED带农历时钟及天气显示(四)
  20. LeetCode——974.和可被K整除的子数组

热门文章

  1. 体素二值膨胀求解采样空间 binary voxel dilation in 3D space
  2. File ‘\‘ is not valid,,Error while building/deploying project . . .
  3. 单端转差分电路详解(1)
  4. 一个人的旅行(Djikstra)
  5. 深度强化学习-基于价值学习的高级技巧(五-1)
  6. 长期默默耕耘在一卡通行业的一个团队
  7. Rime 输入法备份(多电脑同步)
  8. Spark源码解读之Shuffle计算引擎剖析
  9. 建议收藏啊!软件测试人员必备的30个网站清单,果断收藏了!
  10. 利用ffmpeg进行音频转码