Java并发(十四):并发工具类——CountDownLatch
先做总结:
1、CountDownLatch 是什么?
CountDownLatch 允许一个或多个线程等待其他线程(不一定是线程,某个操作)完成之后再执行。
CountDownLatch的构造函数接收一个int类型的参数作为计数器,如果你想等待N个点完成,这里就传入N。
当我们调用一次CountDownLatch的countDown方法时,N就会减1,CountDownLatch的await会阻塞当前线程,直到N变成零。
由于countDown方法可以用在任何地方,所以这里说的N个点,可以是N个线程,也可以是1个线程里的N个执行步骤。
2、实现原理:
(1)CountDownLatch 的sync属性,继承自AQS
(2)CountDownLatch countDownLatch = new CountDownLatch(5);时将countDownLatch.sync.state设置为5
(3)countDownLatch.await(),检查sync.state!=0时,当前线程park(),放入sync的阻塞队列
(4)countDownLatch.countDown(),sync.state - 1,如果发现sync.state==0了,唤醒sync阻塞队列中的线程
3、CountDownLatch 与 CyclicBarrier区别:
(1)CountDownLatch的计数器只能使用一次,而CyclicBarrier可以重复使用(可以重置)。
(2)CyclicBarrier还提供其他有用的方法,比如getNumberWaiting方法可以获得CyclicBarrier阻塞的线程数量。isBroken方法用来知道阻塞的线程是否被中断。
(3)CyclicBarrier针对的是线程,而CountDownLatch针对的是操作(只要调用countDownLatch.countDown()可以)。
一、应用举例
// 老板进入会议室等待5个人全部到达会议室才会开会。所以这里有两个线程老板等待开会线程、员工到达会议室:
class CountDownLatchTest {
private static CountDownLatch countDownLatch = new CountDownLatch(5); // Boss线程,等待员工到达开会
static class BossThread extends Thread {
@Override
public void run() {
System.out.println("Boss在会议室等待,总共有" + countDownLatch.getCount() + "个人开会...");
try {
countDownLatch.await(); // Boss等待
} catch (InterruptedException e) {
e.printStackTrace();
} System.out.println("所有人都已经到齐了,开会吧...");
}
} // 员工到达会议室
static class EmpleoyeeThread extends Thread {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + ",到达会议室...."); // 员工到达会议室 count - 1
countDownLatch.countDown();
}
} public static void main(String[] args) {
// Boss线程启动
new BossThread().start(); // 员工到达会议室
for (int i = 0; i < countDownLatch.getCount(); i++) {
new EmpleoyeeThread().start();
}
}
}
二、类结构
public class CountDownLatch {
private final Sync sync; // 锁
private static final class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 4982264981922014374L;
Sync(int count) {
setState(count);
}
int getCount() {
return getState();
}
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
protected boolean tryReleaseShared(int releases) {
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
}
}
三、原理解析
CountDownLatch countDownLatch = new CountDownLatch(5);
public CountDownLatch(int count) {
if (count < 0)
throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
/**
* CountDownLatch.Sync.Sync(int)
* AQS的state用作count计数
*/
Sync(int count) {
setState(count);
}
countDownLatch.await();
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
/**
* AbstractQueuedSynchronizer.acquireSharedInterruptibly(int)
* 尝试获取锁,获取不到锁,当前进入同步队列并挂起
*/
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0) // 尝试获取锁
doAcquireSharedInterruptibly(arg); // 获取不到锁,当前进入同步队列并挂起
}
/**
* CountDownLatch.Sync.tryAcquireShared(int)
* state/count没有减到0之前不予许拿锁
*/
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
countDownLatch.countDown();
public void countDown() {
sync.releaseShared(1);
}
/**
* AbstractQueuedSynchronizer.releaseShared(int)
*/
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) { // 尝试释放锁
doReleaseShared(); // 释放掉锁之后,唤醒同步队列的线程(调用await()的线程)
return true;
}
return false;
}
/**
* CountDownLatch.Sync.tryReleaseShared(int)
* countDown一次count/state减一
* 直到count/state减到0,return true,允许释放同步队列里的线程
*/
protected boolean tryReleaseShared(int releases) {
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
四、CyclicBarrier和CountDownLatch的区别
- CountDownLatch的计数器只能使用一次。而CyclicBarrier的计数器可以使用reset() 方法重置。所以CyclicBarrier能处理更为复杂的业务场景,比如如果计算发生错误,可以重置计数器,并让线程们重新执行一次。
- CyclicBarrier还提供其他有用的方法,比如getNumberWaiting方法可以获得CyclicBarrier阻塞的线程数量。isBroken方法用来知道阻塞的线程是否被中断。
并发工具类(一)等待多线程完成的CountDownLatch
【死磕Java并发】—–J.U.C之并发工具类:CountDownLatch
Java并发(十四):并发工具类——CountDownLatch的更多相关文章
- Java从零开始学二十四(集合工具类Collections)
一.Collections简介 在集合的应用开发中,集合的若干接口和若干个子类是最最常使用的,但是在JDK中提供了一种集合操作的工具类 —— Collections,可以直接通过此类方便的操作集合 二 ...
- Java笔记(二十四)……集合工具类Collections&Arrays
Collections 集合框架的工具类,方法全部为静态 Collections与Collection的区别 Collection是集合框架的一个顶层接口,里面定义了单列集合的共性方法 Collect ...
- Java并发工具类 - CountDownLatch
Java并发工具类 - CountDownLatch 1.简介 CountDownLatch是Java1.5之后引入的Java并发工具类,放在java.util.concurrent包下面 http: ...
- Java中的4个并发工具类 CountDownLatch CyclicBarrier Semaphore Exchanger
在 java.util.concurrent 包中提供了 4 个有用的并发工具类 CountDownLatch 允许一个或多个线程等待其他线程完成操作,课题点 Thread 类的 join() 方法 ...
- Java并发工具类CountDownLatch源码中的例子
Java并发工具类CountDownLatch源码中的例子 实例一 原文描述 /** * <p><b>Sample usage:</b> Here is a pai ...
- Java并发编程工具类 CountDownLatch CyclicBarrier Semaphore使用Demo
Java并发编程工具类 CountDownLatch CyclicBarrier Semaphore使用Demo CountDownLatch countDownLatch这个类使一个线程等待其他线程 ...
- 线程高级应用-心得6-java5线程并发库中同步工具类(synchronizers),新知识大用途
1.新知识普及 2. Semaphore工具类的使用案例 package com.java5.thread.newSkill; import java.util.concurrent.Executor ...
- 同步工具类 CountDownLatch 和 CyclicBarrier
在开发中,一些异步操作会明显加快执行速度带来更好的体验,但同时也增加了开发的复杂度,想了用好多线程,就必须从这些方面去了解 线程的 wait() notify() notifyall() 方法 线程异 ...
- java中的Arrays这个工具类你真的会用吗
Java源码系列三-工具类Arrays 今天分享java的源码的第三弹,Arrays这个工具类的源码.因为近期在复习数据结构,了解到Arrays里面的排序算法和二分查找等的实现,收益匪浅,决定研读 ...
- Java操作文件夹的工具类
Java操作文件夹的工具类 import java.io.File; public class DeleteDirectory { /** * 删除单个文件 * @param fileName 要删除 ...
随机推荐
- 2017 ACM暑期多校联合训练 - Team 4 1012 HDU 6078 Wavel Sequence (模拟)
题目链接 Problem Description Have you ever seen the wave? It's a wonderful view of nature. Little Q is a ...
- 24、CSS定位
CSS定位方法 driver.find_element_by_css_selector() 1.CSS定位常用策略(方式) 1.id选择器 说明:根据元素id属性来选择 格式:#id 如:#userA ...
- 再续 virtualenv II
为什么搭建虚拟环境 搭建 Python 虚拟环境,可以方便的解决不同项目中对类库的依赖问题.当然,也可以方便地Python2,Python3 共存.避免包的混乱和版本的冲突.为每个程序单独创建虚拟环境 ...
- java在CMD窗口执行程序的时候输入密码(隐藏一些敏感信息)
有时候我们需要从CMD窗口执行一些命令,有时候会输入一些敏感的信息,比如密码之类的东西,所以我们可以从控制台读取但是不希望别人看见我们的密码: import java.io.Console; /** ...
- 使用ctypes在Python中调用C++动态库
使用ctypes在Python中调用C++动态库 入门操作 使用ctypes库可以直接调用C语言编写的动态库,而如果是调用C++编写的动态库,需要使用extern关键字对动态库的函数进行声明: #in ...
- PostGreSQL数据库安装配置说明
windows 10 x64 pro 1703安装postgresql-9.6.3-2-windows-x64.exe数据库,步骤如下: 第一:下载数据库安装程序,下载地址为:https://www. ...
- EasyUi – 5.修改$.messager.show() 弹出窗口在浏览器顶部中间出现
由于在easyui中$.messager.show() 只有一种弹出方式(在浏览器的或下角弹出),我最近在做一个项目的时候需要在浏览器的顶部中间出现.由于自己写花那么多的时间,所以就去修改了原码(不推 ...
- springcloud 显示服务详细健康信息
pom.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns="htt ...
- 在LoadRunner中从数组类型的参数随机取值的方法
在LoadRunner中从数组类型的参数随机取值的方法 使用web_reg_save_param做关联后,有时候会有多个匹配值. 为了模仿用户行为随机取一个值为后续transcation所用,可以使用 ...
- shell脚本中${var1:-var2}
在一个shell脚本中看见一行代码: DATE=${:-`date "+%Y%m%d" -d "-1 day"`} 查了一下 ${var1:-var2} 这种结 ...