多线程编程-- part 7 CountDownLatch
CountDownLatch简介
CountDownLatch是通过“共享锁”实现的。在创建CountDownLatch中时,会传递一个int类型参数count,该参数是“锁计数器”的初始状态,表示该“共享锁”最多能被count给线程同时获取。当某线程调用该CountDownLatch对象的await()方法时,该线程会等待“共享锁”可用时,才能获取“共享锁”进而继续运行。而“共享锁”可用的条件,就是“锁计数器”的值为0!而“锁计数器”的初始值为count,每当一个线程调用该CountDownLatch对象的countDown()方法时,才将“锁计数器”-1;通过这种方式,必须有count个线程调用countDown()之后,“锁计数器”才为0,而前面提到的等待线程才能继续运行!
CountDownLatch和CyclicBarrier的区别
(01) CountDownLatch的作用是允许1或N个线程等待其他线程完成执行;而CyclicBarrier则是允许N个线程相互等待。
(02) CountDownLatch的计数器无法被重置;CyclicBarrier的计数器可以被重置后使用,因此它被称为是循环的barrier。
CountDownLatch函数列表
CountDownLatch(int count)
构造一个用给定计数初始化的 CountDownLatch。 // 使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断。
void await()
// 使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或超出了指定的等待时间。
boolean await(long timeout, TimeUnit unit)
// 递减锁存器的计数,如果计数到达零,则释放所有等待的线程。
void countDown()
// 返回当前计数。
long getCount()
// 返回标识此锁存器及其状态的字符串。
String toString()
学习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 {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}

说明:acquireSharedInterruptibly()的作用是获取共享锁。
如果当前线程是中断状态,则抛出异常InterruptedException。否则,调用tryAcquireShared(arg)尝试获取共享锁;尝试成功则返回,否则就调用doAcquireSharedInterruptibly()。doAcquireSharedInterruptibly()会使当前线程一直等待,直到当前线程获取到共享锁(或被中断)才返回。
tryAcquireShared()在CountDownLatch.java中被重写,它的源码如下:
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
说明:tryAcquireShared()的作用是尝试获取共享锁。
如果"锁计数器=0",即锁是可获取状态,则返回1;否则,锁是不可获取状态,则返回-1。
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 zero
for (;;) {
// 获取“锁计数器”的状态
int c = getState();
if (c == 0)
return false;
// “锁计数器”-1
int nextc = c-1;
// 通过CAS函数进行赋值。
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}

说明:tryReleaseShared()的作用是释放共享锁,将“锁计数器”的值-1。
CountDownLatch实例
public class testHello { 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的数值减1
doneSignal.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
可以看出,主线程通过doneSignal.await()等待其他线程将doneSignal递减至0,其他的几个子线程,每次通过countDown函数将doneSignal值减1。当doneSignal为0时,main被唤醒继续执行。
多线程编程-- part 7 CountDownLatch的更多相关文章
- java核心-多线程-Java多线程编程涉及到包、类
Java有关多线程编程设计的类主要涉及两个包java.lang和java.util.concurrent两个包 java.lang包,主要是线程基础类 <1>Thread <2> ...
- [Java123] JDBC and Multi-Threading 多线程编程学习笔记
项目实际需求:DB交互使用多线程实现 多线程编程基础:1.5 :( (假设总分10) 计划一个半月从头学习梳理Java多线程编程基础以及Oracle数据库交互相关的多线程实现 学习如何通过代码去验证 ...
- Java多线程编程实战指南(核心篇)读书笔记(三)
(尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76686044冷血之心的博客) 博主准备恶补一番Java高并发编程相 ...
- Java多线程编程(5)--线程间通信
一.等待与通知 某些情况下,程序要执行的操作需要满足一定的条件(下文统一将其称之为保护条件)才能执行.在单线程编程中,我们可以使用轮询的方式来实现,即频繁地判断是否满足保护条件,若不满足则继续判断 ...
- 《Java多线程编程实战指南(核心篇)》阅读笔记
<Java多线程编程实战指南(核心篇)>阅读笔记 */--> <Java多线程编程实战指南(核心篇)>阅读笔记 Table of Contents 1. 线程概念 1.1 ...
- Web Worker javascript多线程编程(一)
什么是Web Worker? web worker 是运行在后台的 JavaScript,不占用浏览器自身线程,独立于其他脚本,可以提高应用的总体性能,并且提升用户体验. 一般来说Javascript ...
- Web Worker javascript多线程编程(二)
Web Worker javascript多线程编程(一)中提到有两种Web Worker:专用线程dedicated web worker,以及共享线程shared web worker.不过主要讲 ...
- windows多线程编程实现 简单(1)
内容:实现win32下的最基本多线程编程 使用函数: #CreateThread# 创建线程 HANDLE WINAPI CreateThread( LPSECURITY_ATTRIBUTES lpT ...
- Rust语言的多线程编程
我写这篇短文的时候,正值Rust1.0发布不久,严格来说这是一门兼具C语言的执行效率和Java的开发效率的强大语言,它的所有权机制竟然让你无法写出线程不安全的代码,它是一门可以用来写操作系统的系统级语 ...
随机推荐
- venv转向pipenv
先编译安装你需要的Python版本:参考https://www.cnblogs.com/zxpo/p/10011871.html python3.6安装在:/usr/bin/python3.6目录下: ...
- linux之gzip命令
命令格式: gzip [选项] 压缩(解压缩)的文件名 参数: -d 将压缩文件解压. -l 对每个压缩文件,显示压缩文件的大小,未压缩文件的大小,压缩比,未压缩文件的名字 -v 对每一个压缩和解压 ...
- 代码实现程序启动后, 可以从键盘输入接收多个整数, 直到输入quit时结束输入. 把所有输入的整数倒序排列打印
package com.loaderman.test; import java.util.Comparator; import java.util.Scanner; import java.util. ...
- 使用jQuery做简单的图片轮播效果
一.本特效主要用到的前端知识点 CSS中绝对定位(absolute)CSS实现垂直居中jQuery中简单的淡入淡出动画效果(fadeIn,fadeOut)定时器(setInterval,clear ...
- [idea]添加jar包的方法
一:在项目的根目录下建立lib文件夹,然后将对应的jar包文件拷贝进去. 二:点击项目右键,选择Open Module Settings 三.选择Project Settings->Librar ...
- koa express 优缺点
关于 Express 优点.Express 的优点是线性逻辑:路由和中间件完美融合,通过中间件形式把业务逻辑细分,简化,一个请求进来经过一系列中间件处理后再响应给用户,再复杂的业务也是线性了,清晰明了 ...
- Linux 查看登录用户信息 who & whoami
Linux 查看登录用户信息 who & whoami 在一台服务器上,同一时间往往会有很难多人同时登录. who 命令可以查看当前系统中有哪些人登录,以及他们都工作在哪个控制台上. 这样可以 ...
- IDEA下启动tomcat非常慢
笔者遇到的原因是在setclasspath.bat里面添加了参数 set JAVA_OPTS="-XX:-UseSplitVerifier -noverify -Djava.net.pref ...
- dockerfile中配置时区
https://www.cnblogs.com/kevingrace/p/5570597.html #设置时区RUN /bin/cp /usr/share/zoneinfo/Asia/Shanghai ...
- asp.netMVC中配置automap
第一.新建类库,以解决方案名XXX为例,建立子类库名为 XXX.AutoMapper. 第二. XXX.AutoMapper类库中,添加对automap的引用. 第三.创建映射文件类 ModelPr ...