先做总结:

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的更多相关文章

  1. Java从零开始学二十四(集合工具类Collections)

    一.Collections简介 在集合的应用开发中,集合的若干接口和若干个子类是最最常使用的,但是在JDK中提供了一种集合操作的工具类 —— Collections,可以直接通过此类方便的操作集合 二 ...

  2. Java笔记(二十四)……集合工具类Collections&Arrays

    Collections 集合框架的工具类,方法全部为静态 Collections与Collection的区别 Collection是集合框架的一个顶层接口,里面定义了单列集合的共性方法 Collect ...

  3. Java并发工具类 - CountDownLatch

    Java并发工具类 - CountDownLatch 1.简介 CountDownLatch是Java1.5之后引入的Java并发工具类,放在java.util.concurrent包下面 http: ...

  4. Java中的4个并发工具类 CountDownLatch CyclicBarrier Semaphore Exchanger

    在 java.util.concurrent 包中提供了 4 个有用的并发工具类 CountDownLatch 允许一个或多个线程等待其他线程完成操作,课题点 Thread 类的 join() 方法 ...

  5. Java并发工具类CountDownLatch源码中的例子

    Java并发工具类CountDownLatch源码中的例子 实例一 原文描述 /** * <p><b>Sample usage:</b> Here is a pai ...

  6. Java并发编程工具类 CountDownLatch CyclicBarrier Semaphore使用Demo

    Java并发编程工具类 CountDownLatch CyclicBarrier Semaphore使用Demo CountDownLatch countDownLatch这个类使一个线程等待其他线程 ...

  7. 线程高级应用-心得6-java5线程并发库中同步工具类(synchronizers),新知识大用途

    1.新知识普及 2. Semaphore工具类的使用案例 package com.java5.thread.newSkill; import java.util.concurrent.Executor ...

  8. 同步工具类 CountDownLatch 和 CyclicBarrier

    在开发中,一些异步操作会明显加快执行速度带来更好的体验,但同时也增加了开发的复杂度,想了用好多线程,就必须从这些方面去了解 线程的 wait() notify() notifyall() 方法 线程异 ...

  9. java中的Arrays这个工具类你真的会用吗

    Java源码系列三-工具类Arrays ​ 今天分享java的源码的第三弹,Arrays这个工具类的源码.因为近期在复习数据结构,了解到Arrays里面的排序算法和二分查找等的实现,收益匪浅,决定研读 ...

  10. Java操作文件夹的工具类

    Java操作文件夹的工具类 import java.io.File; public class DeleteDirectory { /** * 删除单个文件 * @param fileName 要删除 ...

随机推荐

  1. 牛客网习题剑指offer之数值的整数次方

    分析: 要考虑到exponent为0和负数的情况. 如果base是0并且exponent是负数的时候呢?那就发生除0的情况了. AC代码: public class Solution { public ...

  2. 打表找规律C - Insertion Sort Gym - 101955C

    题目链接:https://cn.vjudge.net/contest/273377#problem/C 给你 n,m,k. 这个题的意思是给你n个数,在对前m项的基础上排序的情况下,问你满足递增子序列 ...

  3. python并发编程之asyncio协程(三)

    协程实现了在单线程下的并发,每个协程共享线程的几乎所有的资源,除了协程自己私有的上下文栈:协程的切换属于程序级别的切换,对于操作系统来说是无感知的,因此切换速度更快.开销更小.效率更高,在有多IO操作 ...

  4. Linux用户密码期限修改

    今天有开发报故,sftp无法登录.检查服务都是正常的,之前3月份也出现过此问题,当时忙没有注意,现在看每3个月出现问题.这才想到是密码过期导致的. 先重置用户密码,发现过期日志为Oct 08, 201 ...

  5. Reverse Linked List I&&II——数据结构课上的一道题(经典必做题)

    Reverse Linked List I Question Solution Reverse a singly linked list. Reverse Linked List I 设置三个指针即可 ...

  6. Hadoop2.5.2 安装部署

    0x00 平台环境 OS: CentOS-6.5-x86_64 JDK: jdk-8u111-linux-x64 Hadoop: hadoop-2.5.2 0x01 操作系统基本设置 1.1 网络配置 ...

  7. MySQL----示例知识点整理

    示例语句: ),hour(c.created_at) from `behavior_client_view` c join `behavior_share` s on c.share_uuid=s.u ...

  8. NIO-4pipe

    import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.Pipe; import org.ju ...

  9. svm 中采用自动搜索参数的方式获得参数值

    载时自http://blog.csdn.net/u011177305/article/details/46458801?locationNum=1 OpenCV中SVM类是提供了优化参数值功能的,下面 ...

  10. Wannafly挑战赛18 C - 异或和

    思路:我刚开始是想旋转四次坐标,每次用bit计算每个点左上角的点到这个点的距离,TLE了.... 这种算曼哈顿距离的可以将x 轴和 y 轴独立开来,分别计算. #include<bits/std ...