CountDownLatch介绍

CountDownLatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。

uml类图

CountDownLatch的数据结构很简单,它是通过”共享锁”实现的。它包含了sync对象,sync是Sync类型。Sync是实例类,它继承于AQS。

CountDownLatch源码分析

1. CountDownLatch(int count)

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

该函数是创建一个Sync对象,而Sync是继承于AQS类。Sync构造函数如下:

Sync(int count) {setState(count);
}

setState()在AQS中实现,源码如下:

protected final void setState(long newState) {state = newState;
}

说明:在AQS中,state是一个private volatile long类型的对象。对于CountDownLatch而言,state表示的”锁计数器“。CountDownLatch中的getCount()最终是调用AQS中的getState(),返回的state对象,即”锁计数器“。

2.await()

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

说明:该函数实际上是调用的AQS的acquireSharedInterruptibly(1);

AQS中的acquireSharedInterruptibly()的源码如下:

public final void acquireSharedInterruptibly(long arg)throws InterruptedException {//如果当前线程是中断状态,则抛出异常InterruptedExceptionif (Thread.interrupted())throw new InterruptedException();//调用tryAcquireShared(arg)尝试获取共享锁,尝试成功则返回//否则就调用doAcquireSharedInterruptibly()if (tryAcquireShared(arg) < 0)doAcquireSharedInterruptibly(arg);
}

tryAcquireShared()在CountDownLatch.java中被重写,它的源码如下:

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

如果”锁计数器=0”,即锁是可获取状态,则返回1;否则,锁是不可获取状态,则返回-1。

doAcquireSharedInterruptibly()方法

private void doAcquireSharedInterruptibly(long arg)throws InterruptedException {// 创建"当前线程"的Node节点,且Node中记录的锁是"共享锁"类型;并将该节点添加到CLH队列末尾。final Node node = addWaiter(Node.SHARED);boolean failed = true;try {for (;;) {// 获取上一个节点。// 如果上一节点是CLH队列的表头,则"尝试获取共享锁"。final Node p = node.predecessor();if (p == head) {long r = tryAcquireShared(arg);if (r >= 0) {setHeadAndPropagate(node, r);p.next = null; // help GCfailed = false;return;}}// (上一节点不是CLH队列的表头) 当前线程一直等待,直到获取到共享锁。// 如果线程在等待过程中被中断过,则再次中断该线程(还原之前的中断状态)。if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())throw new InterruptedException();}} finally {if (failed)cancelAcquire(node);}
}

doAcquireSharedInterruptibly()会使当前线程一直等待,直到当前线程获取到共享锁(或被中断)才返回。跟共享锁ReadLock的doAcquireShare()方法非常类似,这里就不进行赘述了。

3. countDown()

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

说明:该函数实际上调用releaseShared(1)释放共享锁。
releaseShared()在AQS中实现,源码如下:

public final boolean releaseShared(int arg) {if (tryReleaseShared(arg)) {doReleaseShared();return true;}return false;
}

说明:releaseShared()的目的是让当前线程释放它所持有的共享锁。
它首先会通过tryReleaseShared()去尝试释放共享锁。尝试成功,则直接返回;尝试失败,则通过doReleaseShared()去释放共享锁。

tryReleaseShared()在CountDownLatch.java中被重写,源码如下:

protected boolean tryReleaseShared(int releases) {// Decrement count; signal when transition to zerofor (;;) {// 获取“锁计数器”的状态int c = getState();if (c == 0)return false;// “锁计数器”-1int nextc = c-1;// 通过CAS函数进行赋值。if (compareAndSetState(c, nextc))return nextc == 0;}
}

说明:tryReleaseShared()的作用是释放共享锁,将“锁计数器”的值-1。

总结:CountDownLatch是通过“共享锁”实现的。在创建CountDownLatch中时,会传递一个int类型参数count,该参数是“锁计数器”的初始状态,表示该“共享锁”最多能被count给线程同时获取。当某线程调用该CountDownLatch对象的await()方法时,该线程会等待“共享锁”可用时,才能获取“共享锁”进而继续运行。而“共享锁”可用的条件,就是“锁计数器”的值为0!而“锁计数器”的初始值为count,每当一个线程调用该CountDownLatch对象的countDown()方法时,才将“锁计数器”-1;通过这种方式,必须有count个线程调用countDown()之后,“锁计数器”才为0,而前面提到的等待线程才能继续运行!

CountDownLatch的使用示例

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.CyclicBarrier;public class CountDownLatchTest1 {private static int LATCH_SIZE = 5;private static CountDownLatch doneSignal;public static void main(String[] args) {try {doneSignal = new CountDownLatch(LATCH_SIZE);// 新建5个任务for(int i=0; i<LATCH_SIZE; i++)new InnerThread().start();System.out.println("main await begin.");// "主线程"等待线程池中5个任务的完成doneSignal.await();System.out.println("main await finished.");} catch (InterruptedException e) {e.printStackTrace();}}static class InnerThread extends Thread{public void run() {try {Thread.sleep(1000);System.out.println(Thread.currentThread().getName() + " sleep 1000ms.");// 将CountDownLatch的数值减1doneSignal.countDown();} catch (InterruptedException e) {e.printStackTrace();}}}
}

运行结果:

main await begin.
Thread-0 sleep 1000ms.
Thread-2 sleep 1000ms.
Thread-1 sleep 1000ms.
Thread-4 sleep 1000ms.
Thread-3 sleep 1000ms.
main await finished.

JUC锁-CountDownLatch(六)相关推荐

  1. Java多线程系列---“JUC锁”01之 框架

    本章,我们介绍锁的架构:后面的章节将会对它们逐个进行分析介绍.目录如下: 01. Java多线程系列--"JUC锁"01之 框架 02. Java多线程系列--"JUC锁 ...

  2. Java多线程系列--“JUC锁”03之 公平锁(一)

    概要 本章对"公平锁"的获取锁机制进行介绍(本文的公平锁指的是互斥锁的公平锁),内容包括: 基本概念 ReentrantLock数据结构 参考代码 获取公平锁(基于JDK1.7.0 ...

  3. JUC锁框架AbstractQueuedSynchronizer详细分析

    转载自:https://www.jianshu.com/p/0da2939391cf AQS是JUC锁框架中最重要的类,通过它来实现独占锁和共享锁的.本章是对AbstractQueuedSynchro ...

  4. JUC锁框架_AbstractQueuedSynchronizer详细分析

    AQS是JUC锁框架中最重要的类,通过它来实现独占锁和共享锁的.本章是对AbstractQueuedSynchronizer源码的完全解析,分为四个部分介绍: CLH队列即同步队列:储存着所有等待锁的 ...

  5. Java多线程系列--“JUC锁”05之 非公平锁

    转载自:http://www.cnblogs.com/skywang12345/p/3496651.html点击打开链接 概要 前面两章分析了"公平锁的获取和释放机制",这一章开始 ...

  6. JUC锁框架——AQS源码分析

    2019独角兽企业重金招聘Python工程师标准>>> JUC锁介绍 Java的并发框架JUC(java.util.concurrent)中锁是最重要的一个工具.因为锁,才能实现正确 ...

  7. JUC并发编程六 并发架构--偏向锁

    偏向锁 对象默认开启了偏向锁. import lombok.extern.slf4j.Slf4j; import org.openjdk.jol.info.ClassLayout;@Slf4j(top ...

  8. JUC锁-框架与基本概念(一)

    框架与基本概念 在了解后面的内容之前,必须要先了解基本概念: AQS – 指AbstractQueuedSynchronizer类. AQS是java中管理"锁"的抽象类,锁的许多 ...

  9. JUC之CountDownLatch的源码和使用场景分析

    最近工作不饱和,写写文章充充电.何以解忧,唯有Coding.后续更新的文章涉及的方向有:ThreadPoolExecutor.Spring.MyBatis.ReentrantLock.CyclicBa ...

最新文章

  1. python了解一下_Python发展史了解一下
  2. 【转】CT图像重构方法详解——傅里叶逆变换法、直接反投影法、滤波反投影法
  3. Leetcode--23.合并K个排序链表(Java)
  4. python requests 代理ip_python requests 测试代理ip
  5. 【VB.NET】基于Visual Studio编写VB.NET程序的常见问题的解答
  6. Xshell远程访问工具及epel-release包安装
  7. 关于idea Tomcat部署的一个小坑
  8. 软件测试实验1:JUnit、Hamcrest、Eclemma
  9. 报表中去除字符中的空格
  10. allure 测试报告本地打开_Allure自动化测试报告我是这样用的
  11. PMP之四个敏捷会议
  12. Github没有Download Zip(下载zip)的绿色选项是因为所在的是一个子目录
  13. 你还在为不知道怎么给家人庆祝生日而发愁吗?
  14. 体系结构24_输入输出系统(1)
  15. L'Hospital法则
  16. vscode遇到无法访问此网站问题的两种解决方法
  17. 不定期备考小tips[数模][0] #20210529
  18. CleanMyMac X免费吗?怎么下载2023最新版
  19. Pandas库入门详细教程
  20. 跨局域网远程连接神器——frp内网穿透

热门文章

  1. Ring3下Dll注入方法整理汇总
  2. 透过汇编另眼看世界之函数调用
  3. 网狐棋牌(二) CQueueServiceEvent初步分析
  4. RedrawWindow, UpdateWindow,InvalidateRect 用法
  5. Kafka解惑之Old Producer(2)——Sync Analysis
  6. 设计模式:组合模式(Composite)
  7. Leetcode-Merge k Sorted Lists
  8. 【线上圆桌整理 - 微软】后疫情时代现代化办公新趋势
  9. 和Google 微帧 Hulu Hotstar 爱奇艺 火花思维 猿辅导 新浪微博的专家聊聊Codec
  10. mac安装QT及QT基本使用