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 要删除 ...
随机推荐
- Hash破解神器:Hashcat的简单使用
Hash破解神器:Hashcat的简单使用 2014-06-10 21:02:42| 分类: 离线密码破解 | 标签:密码字典 rar密码破解 zip密码破解 密码破解 |举报|字号 订阅 ...
- Python设计模式中单例模式的实现及在Tornado中的应用
单例模式的实现方式 将类实例绑定到类变量上 class Singleton(object): _instance = None def new(cls, *args): if not isinstan ...
- ubuntu遇到的 the system is runing low-graphics mode 问题
不知道修改了什么,然后开机显示the system is runing low-graphics mode 看过博客使用如下方法成功进入系统,但是显示分辨率很低,显示 built-in display ...
- caffe Python API 之Model训练
# 训练设置 # 使用GPU caffe.set_device(gpu_id) # 若不设置,默认为0 caffe.set_mode_gpu() # 使用CPU caffe.set_mode_cpu( ...
- js完成密码输入为空,和两次输入不一致
<!DOCTYPE html><html><body> <script language="javascript"> functio ...
- Debian系网络配置 /etc/network/interfaces
说Debian系的网卡配置跟Redhat系很不一样,Redhat是放在/etc/sysconfig/network-scripts目录下面的一大堆文件里面,要修改?你一个一个文件来过吧.Debian系 ...
- Denoise Autoencoder简单理解
自编码器通过学习隐含特征来表达原始数据,那什么是denoise autoencoder呢? 关于Autoencoder参考:http://blog.csdn.net/on2way/article/de ...
- 《HBase权威指南》学习笔记
第一章 简介 背景: GFS:集群存储海量数据,数据在节点间冗余复制,即使一台存储服务器发生故障,也不会影响可用性. GFS的缺点:适合存储少许非常大的文件,而不适合存储大量小文件,因为文件的元数据 ...
- DOM的查找与操作
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...
- AC日记——830A - Office Keys
思路: 背包: 代码: #include <cmath> #include <cstdio> #include <cstring> #include <ios ...