当前位置:网站首页>AQS 之 CountdownLatch 源码分析
AQS 之 CountdownLatch 源码分析
2022-06-09 05:11:00 【smartjiang-java】
1:CountdownLatch 基本知识
1:CountDownLatch 允许一个或多个线程阻塞,等待其他线程完成操作。
2:有一个计数器,表示需要等待的事件数量
3:进入终止状态后,不可重置,不能重复使用。
2:构造方法
传入 int 整数,作为初始化计数器的值
public CountDownLatch(int count) {
// int 数值 < 0 ,抛出异常
if (count < 0) throw new IllegalArgumentException("count < 0");
// 进入 Sync(count) 方法
this.sync = new Sync(count);
}
进入 Sync(count) 方法
Sync(int count) {
// 把传入的 int 数值作为 AQS 的 state 的初始值
setState(count);
}
3:阻塞等待方法
调用 await() 方法
public void await() throws InterruptedException {
// 进入 acquireSharedInterruptibly(1) 方法
sync.acquireSharedInterruptibly(1);
}
进入 acquireSharedInterruptibly(1) 方法
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
// 检查中断
if (Thread.interrupted())
throw new InterruptedException();
// 进入 tryAcquireShared(1) 方法
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
进入 tryAcquireShared(1) 方法
protected int tryAcquireShared(int acquires) {
// 判断 state 的数目是否等于 0 ,是返回 1,否则返回 -1.我们假设返回 -1
return (getState() == 0) ? 1 : -1;
}
回到 acquireSharedInterruptibly(1) 方法
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// tryAcquireShared(1) 返回 -1 ,< 0
if (tryAcquireShared(arg) < 0)
// 进入 doAcquireSharedInterruptibly(1) 方法
doAcquireSharedInterruptibly(arg);
}
进入 doAcquireSharedInterruptibly(1) 方法
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
// 根据当前线程创建一个节点,作为等待队列的尾节点
// 如果是第一个进入等待队列的,会创建一个亚元节点,作为头节点
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head) {
// 再次判断 state 的值 是否等于0,返回 -1
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
failed = false;
return;
}
}
// shouldParkAfterFailedAcquire() :将当前节点的前一个节点的 waitStatus 从 0 变成 -1
// parkAndCheckInterrupt():使当前线程进入阻塞状态。当被唤醒后,继续进入 循环
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
3:countDown 方法
调用 countDown() 方法,使 state 的值 -1
public void countDown() {
// 进入 releaseShared(1) 方法
sync.releaseShared(1);
}
进入 releaseShared(1) 方法
public final boolean releaseShared(int arg) {
// 进入 tryReleaseShared(1) 方法
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
进入 tryReleaseShared(1) 方法
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
// 获取 state 的值
int c = getState();
// state 等于0 ,返回 false
if (c == 0)
return false;
// state >0 ,减1,并通过 cas 去更新 state 的值 ,再去判断 state 的值是否等于0 ,我们假设返回 true
int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
}
回到 releaseShared(1) 方法
public final boolean releaseShared(int arg) {
// tryReleaseShared(1) 返回 true
if (tryReleaseShared(arg)) {
// 进入 doReleaseShared(1) 方法
doReleaseShared();
return true;
}
return false;
}
进入 doReleaseShared(1) 方法
private void doReleaseShared() {
for (;;) {
Node h = head;
// 等待队列中有至少两个节点
if (h != null && h != tail) {
// 判断头节点的 waitStatus 是否等于 -1
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {
// cas 将头节点的 waitStatus 修改成 0 成功
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue;
// 进入 unparkSuccessor(h) 方法 ,将 头节点之后的第二个节点解除阻塞。
// ps:解除阻塞的线程在 doAcquireSharedInterruptibly(1) 方法里的 for 循环运行
unparkSuccessor(h);
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue; // loop on failed CAS
}
if (h == head) // loop if head changed
break;
}
}
进入 unparkSuccessor(h) 方法
private void unparkSuccessor(Node node) {
// 拿到头节点的 waitStatus 值 0
int ws = node.waitStatus;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
// 取到头节点的后一个节点 s
Node s = node.next;
if (s == null || s.waitStatus > 0) {
s = null;
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
// 让头节点后的第二个节点解除阻塞状态
if (s != null)
LockSupport.unpark(s.thread);
}
边栏推荐
- 记录一次将dmp文件导入oracle数据库(本地导线上),所遇到的问题及解决方法
- Openstack Learning Series 1: openstack introduction, installation and deployment of basic environment
- Previous improvements of CSDN products (up to issue 29)
- 关于全局异常捕获的思考-真正的全局异常捕获
- Intranet penetration hash delivery attack
- 聊聊保证线程安全的10个小技巧
- Penetration test path dictionary, blasting dictionary
- Transformer裏面的緩存機制
- The half year revenue of mushroom street was 168million yuan: a year-on-year decrease of 29% and an operating loss of 240million yuan
- Why do it systems need observability?
猜你喜欢

2022 R2 mobile pressure vessel filling test simulation 100 questions and simulation test

1030. 距离顺序排列矩阵单元格●

ps如何给图像加白边

Openstack Learning Series 1: openstack introduction, installation and deployment of basic environment

数据库的三大范式

故障排查:阿里云轻量应用服务器中的MySQL容器自行停止

PS how to border an image

Cuijian hasn't changed. BAIC Jihu should make a change
![[004] [esp32 Development Notes] audio development framework ADF environment construction - based on esp-idf](/img/55/9eb286bc56ec991837fc014b42fc20.png)
[004] [esp32 Development Notes] audio development framework ADF environment construction - based on esp-idf

Simulated 100 questions and answers of high voltage electrician examination in 2022
随机推荐
Ribbon和Feign的对比-带简易例子
^26 browser kernel
[django learning notes - 12]: database operation
Test question bank and online simulation test for operation certificate of main principals of hazardous chemical business units in 2022
在渗透测试中快速检测常见中间件、组件的高危漏洞
wps ppt背景图片如何换颜色
Why do I need a thread pool? What is pooling technology?
Thinking about global exception capture - real global exception capture
[006] [ESP32开发笔记] 使用Flash下载工具烧录固件步骤
2022 welder (elementary) special operation certificate examination question bank and simulation examination
Troubleshooting: MySQL containers in alicloud lightweight application servers stop automatically
Baidu AI Cloud's revenue in 2021 was RMB 15.1 billion, a year-on-year increase of 64%
[Django学习笔记 - 12]:数据库操作
Ribbon vs feign - with simple examples
Camtasia studio2022 activation code serial number
Lighting - 光的亮度衰减
Myql error expression 1 of select list is not in group by claim and contains nonaggregated column
Cuijian hasn't changed. BAIC Jihu should make a change
Talk about 10 tips to ensure thread safety
Load research of Marathon LB