当前位置:网站首页>13 - JUC CountDownLatch concurrent programming
13 - JUC CountDownLatch concurrent programming
2022-08-01 07:02:00 【Pinellia (•̤̀ᵕ•̤́๑)ᵒᵏᵎᵎᵎᵎ】
CountDownLatch
什么是CountDownLatch
A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.
A CountDownLatch is initialized with a given count. The await methods block until the current count reaches zero due to invocations of the countDown() method, after which all waiting threads are released and any subsequent invocations of await return immediately. This is a one-shot phenomenon – the count cannot be reset. If you need a version that resets the count, consider using a CyclicBarrier.
A CountDownLatch is a versatile synchronization tool and can be used for a number of purposes. A CountDownLatch initialized with a count of one serves as a simple on/off latch, or gate: all threads invoking await wait at the gate until it is opened by a thread invoking countDown(). A CountDownLatch initialized to N can be used to make one thread wait until N threads have completed some action, or some action has been completed N times.
A useful property of a CountDownLatch is that it doesn’t require that threads calling countDown wait for the count to reach zero before proceeding, it simply prevents any thread from proceeding past an await until all threads could pass.
Sample usage: Here is a pair of classes in which a group of worker threads use two countdown latches:
- The first is a start signal that prevents any worker from proceeding until the driver is ready for them to proceed;
- The second is a completion signal that allows the driver to wait until all workers have completed.
上面这段话来自Oracle官方解释.
CountDownLatchIt is an auxiliary tool for thread synchronization,He can make one or more threads wait,until some operations in other threads complete,Then the previously waiting thread is released.His main idea is to initialize with a given counter,It then provides us with two core methods,await()和countDown()方法.通过调用await()方法去阻塞线程,until due to the callcountDown()method decrements the current counter by 0.Then all wereawait()threads are released,Of course this process is a one-off,If you want to implement repeat count,可以用 CyclicBarrier.基于以上的理解,We can get two basic usage scenarios for him
- 初始化计数器为1,Simulate a simple opening and closing latch,Let all threads go through
await()kept out of the latch,until a coordinating thread calls itcountDown()方法将计数器减1,Instantly all threads blocking the door can pass through the latch. - 初始化计数器为N,Make a thread wait outside the door,等NThreads complete their work to open the door,Let the waiting thread go through the latch.
Let's take a look at it with two examples.
应用场景
例1:School sports meet,The 100-meter race is underway.All the athletes are waiting at the starting line,As long as the referee whistle blows,Athletes can start playing immediately,Then wait for all athletes to finish the race,The referee can record the score,宣布比赛结束.This example can be abstracted into two multi-threading problems:
- 有N个线程(运动员)Need to wait for a thread(裁判)give a signal,才可以开始工作
- 有一个线程(裁判)Need to wait for the othersN个线程(运动员)both complete their respective jobs,Only then can he start his work
public class Referee {
public static void main(String[] args) throws Exception {
// Simulate the first problem
CountDownLatch startSignal = new CountDownLatch(1);
// Simulate the second problem
CountDownLatch doneSignal = new CountDownLatch(6);
// 1.1 我们创建6个线程,并调用start方法,The simulation has six athletes preparing to compete at the same time
for (int i = 0; i < 6; i++) {
new Thread(new Player(startSignal, doneSignal), "player " + i).start();
}
// The referee does some pre-match checks,检查OKWhistle afterward,比赛开始
doReadyWork(startSignal);
// Wait for all players to finish the game,记录分数
recordScore(doneSignal);
}
private static void doReadyWork(CountDownLatch startSignal) {
try {
// The referee checks that everything is ready
System.out.println("Ready..");
Thread.sleep(3000);
System.out.println("Go...");
// 1.3 调用countDown()method to open the latch,The mock check is complete,吹口哨,All athletes begin
startSignal.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private static void recordScore(CountDownLatch doneSignal) {
try {
// 2.1 裁判通过await()method blocks this,Wait for the athlete over there to finish the game,将doneSignal的计数器减为0,He started to work
doneSignal.await();
System.out.println("Record the score...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Player implements Runnable{
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;
public Player(CountDownLatch startSignal, CountDownLatch doneSignal) {
this.startSignal = startSignal;
this.doneSignal = doneSignal;
}
@Override
public void run() {
try {
// 1.2 调用await()method to block each thread,Simulate all the athletes waiting over there for the referee to whistle,When the whistle blows, the game begins
startSignal.await();
beginPlay();
// 2.2 doneSignal的计数器为6,Each athlete ends the game,计数器减1,wait until reduced to0,Indicates that everyone has finished the game,
// 那边通过doneSignalThe blocked thread can also start doing its thing
doneSignal.countDown();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void beginPlay() {
try {
System.out.println(Thread.currentThread().getName() + " begin...");
Thread.sleep(5000);
System.out.println(Thread.currentThread().getName() + " complete...");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
执行结果:
Ready..
Go...
player 1 begin...
player 0 begin...
player 2 begin...
player 4 begin...
player 3 begin...
player 5 begin...
player 2 complete...
player 0 complete...
player 1 complete...
player 4 complete...
player 5 complete...
player 3 complete...
Record the score...
源码分析
The code below relies on pairsAQS的理解,参考:并发编程12-ThreadPoolExecutorUse and principle exploration
初始化方法
// 初始化方法,和其他基于AQS的工具一样,Write an inner classSync继承AQS,Set the value of the counter toAQS的state
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
Sync(int count) {
setState(count);
}
await()方法
// await()方法,Here, the parent class template method is still called
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// This defines the template process for acquiring shared locks,The actual logic is left to subclasses to implement,就会走到CountDownLatch的tryAcquireShared(arg)方法中
// 参考下面的方法,如果tryAcquireShared(arg) > 0,Indicates that the counter has been decremented by another thread0,程序正常执行
// 如果tryAcquireShared(arg) < 0,Indicates that the counter has not been decremented0,调用await()The thread of the method needs to block itself.
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
protected int tryAcquireShared(int acquires) {
// 判断stateThat is, whether the counter is equal to or not0
return (getState() == 0) ? 1 : -1;
}
countDown()方法
// countDown()方法,Still the same way,调用AQS的releaseShared(1)方法
public void countDown() {
sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
// 老套路,Call the method overridden by the subclass to release the shared lock
if (tryReleaseShared(arg)) {
doReleaseShared(); // 标记2
return true;
}
return false;
}
protected boolean tryReleaseShared(int releases) {
// Guaranteed by the spin methodCASModify the value operation can be successfully executed
for (;;) {
int c = getState();
// 如果已经等于0,直接返回
if (c == 0)
return false;
int nextc = c-1;
// CAS修改计数器的值,Returns whether the counter is equal0,If get heretrue,Indicates that the current thread decrements the counter to0了,You need to enter the marker2的代码
// Release is still pendingawait()阻塞的线程
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
边栏推荐
- R语言使用tidyquant包的tq_transmute函数计算持有某只股票的天、月、周收益率、ggplot2使用条形图可视化股票月收益率数据、使用百分比显示Y轴坐标数据、使用不同的色彩表征正负收益率
- 从离线到实时对客,湖仓一体释放全量数据价值
- 声音信号处理基频检测和时频分析
- 深度比较两个对象是否相同
- 【音视频】srs直播平台搭建
- 测试工具(四)Jenkins环境搭建与使用
- Datagrip error "The specified database userpassword combination is rejected..."Solutions
- WebSocket implements chat function
- Offer brush questions - 1
- uva10825
猜你喜欢

仿牛客网讨论社区项目—项目总结及项目常见面试题

first unique character in characters

从离线到实时对客,湖仓一体释放全量数据价值

Motion analysis and parameter optimization of crank-slider mechanism

特殊的日子,值得纪念

Flip letters using string container

I have three degrees, and I have five faces. I was "confessed" by the interviewer, and I got an offer of 33*15.

MySQL row locks and gap locks

湖仓一体电商项目(一):项目背景和架构介绍

【音视频】srs直播平台搭建
随机推荐
第02章 MySQL的数据目录【1.MySQL架构篇】【MySQL高级】
leetcode125 Verify palindrome string
太厉害了,终于有人能把文件上传漏洞讲的明明白白了
「游戏引擎 浅入浅出」4.1 Unity Shader和OpenGL Shader
Talk about the bugs in using for in to traverse the array in js
深度比较两个对象是否相同
LeetCode每日一题(309. Best Time to Buy and Sell Stock with Cooldown)
05-SDRAM:仲裁
零代码网站开发利器:WordPress
LeetCode 0149. Maximum number of points on a line
日志导致线程Block的这些坑,你不得不防
The BP neural network based on MATLAB voice characteristic signal classification
爬虫基本原理介绍、实现以及问题解决
MATLAB program design and application of MATLAB 2.5
「面经分享」西北大学 | 字节 生活服务 | 一面二面三面 HR 面
Golang:go模版引擎的使用
Vim扩展内容
Json对象和Json字符串的区别
Windows taskbar icon abnormal solution
对于升级go1.18的goland问题