当前位置: 首页 > news >正文

java CountDownLatch和CyclicBarrier

专栏系列文章地址:https://blog.csdn.net/qq_26437925/article/details/145290162

本文目标:

  1. 理解CountDownLatch和CyclicBarrier的使用,主要是复习Aqs

另外工作中用到CountDownLatch的地方还很多,一般是完成某些事情才能继续某项操作

  • 单词1: countdown
常见释义:[ˈkaʊntdaʊn][ˈkaʊntdaʊn]
n.	倒数读秒,倒计时(如发射宇宙飞船时); 大事临近的时期;
[例句]The countdown to Christmas starts here.
现在开始圣诞节倒计时。
[其他]	复数:countdowns
  • 单词2: latch
常见释义 英[lætʃ][lætʃ]
n.	插销; 门闩; 弹簧锁; 碰锁;
vt.	用插销插上; 用碰锁锁上;
[例句]He lifted the latch and opened the door.
他拉起门闩开了门。
[其他]	第三人称单数:latches 复数:latches 现在分词:latching 过去式:latched 过去分词:latched

目录

  • CountDownLatch (做减法,例子:六国逐一灭,秦统一)
    • CountDownLatch源码
      • countDownLatch.countDown()
      • countDownLatch.await()
  • CyclicBarrier(做加法,例子:召唤神龙,要收集到七龙珠)

CountDownLatch (做减法,例子:六国逐一灭,秦统一)

A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.

public class Main {public static void main(String[] args) throws Exception {CountDownLatch countDownLatch = new CountDownLatch(6);for (int i = 1; i <= 6; i++) {new Thread(() -> {System.out.println(Thread.currentThread().getName() + "国,被灭");countDownLatch.countDown(); // count 减一}, "" + i).start();}// 一直等待,直到数字达到0,放行。countDownLatch.await();System.out.println(Thread.currentThread().getName() + "\t **************秦帝国,统一华夏");closeDoor();}private static void closeDoor() throws InterruptedException {CountDownLatch countDownLatch = new CountDownLatch(6);for (int i = 1; i <= 6; i++) {new Thread(()->{System.out.println(Thread.currentThread().getName()+"\t上完自习,离开教室");countDownLatch.countDown();}, "thread"+String.valueOf(i)).start();}// 等待,减少数字达到0,放行。countDownLatch.await();System.out.println(Thread.currentThread().getName()+"\t **************班长最后关门走人");}
}

CountDownLatch源码

自定义Sync类继承AbstractQueuedSynchronizer,利用AQS自身的状态变量state代表数量(初始化的时候指定),countdown操作让状态只减1(具体是CAS操作compareAndSetState方法让state减少1)

public class CountDownLatch {/*** Synchronization control For CountDownLatch.* Uses AQS state to represent count.*/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) {// Decrement count; signal when transition to zerofor (;;) {int c = getState();if (c == 0)return false;int nextc = c-1;if (compareAndSetState(c, nextc))return nextc == 0;}}}private final Sync sync;public void countDown() {sync.releaseShared(1);}
  • unsafe.compareAndSwapInt方法
/*** Atomically sets synchronization state to the given updated* value if the current state value equals the expected value.* This operation has memory semantics of a {@code volatile} read* and write.** @param expect the expected value* @param update the new value* @return {@code true} if successful. False return indicates that the actual*         value was not equal to the expected value.*/
protected final boolean compareAndSetState(int expect, int update) {// See below for intrinsics setup to support thisreturn unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}

countDownLatch.countDown()

在这里插入图片描述

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

使用了Aqs的releaseShared方法

/*** Releases in shared mode.  Implemented by unblocking one or more* threads if {@link #tryReleaseShared} returns true.** @param arg the release argument.  This value is conveyed to*        {@link #tryReleaseShared} but is otherwise uninterpreted*        and can represent anything you like.* @return the value returned from {@link #tryReleaseShared}*/
public final boolean releaseShared(int arg) {// 如果 tryReleaseShared 返回 false,则 releaseShared 返回false// 如果 tryReleaseShared 返回 true, 执行 doReleaseSharedif (tryReleaseShared(arg)) {doReleaseShared();return true;}return false;
}
  • countDownLatch 的tryReleaseShared方法:不断的while循环CAS操作让state减少1,如果成功就返回true;如果state已经等于0了,就直接返回false
protected boolean tryReleaseShared(int releases) {// Decrement count; signal when transition to zerofor (;;) {int c = getState();if (c == 0)return false;int nextc = c-1;if (compareAndSetState(c, nextc))return nextc == 0;}
}
  • aqs的doReleaseShared方法
  1. doReleaseShared会尝试唤醒head后继的代表线程,如果线程已经唤醒,则仅仅设置PROPAGATE状态
  2. 步骤一的“尝试唤醒head后继的代表线程”和“设置PROPAGATE状态”都是CAS操作,如果CAS失败,则会循环再次尝试
/**
* Release action for shared mode -- signals successor and ensures
* propagation. (Note: For exclusive mode, release just amounts
* to calling unparkSuccessor of head if it needs signal.)
*/
private void doReleaseShared() {/** Ensure that a release propagates, even if there are other* in-progress acquires/releases.  This proceeds in the usual* way of trying to unparkSuccessor of head if it needs* signal. But if it does not, status is set to PROPAGATE to* ensure that upon release, propagation continues.* Additionally, we must loop in case a new node is added* while we are doing this. Also, unlike other uses of* unparkSuccessor, we need to know if CAS to reset status* fails, if so rechecking.*/for (;;) {Node h = head;if (h != null && h != tail) {int ws = h.waitStatus;if (ws == Node.SIGNAL) {if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))continue;            // loop to recheck casesunparkSuccessor(h);}else if (ws == 0 &&!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))continue;                // loop on failed CAS}if (h == head)                   // loop if head changedbreak;}
}

countDownLatch.await()

在这里插入图片描述

/**当前线程一直等待直到countDown到0,或者线程有interrupted异常抛出;如果count本来就是0,那么该方法直接返回* Causes the current thread to wait until the latch has counted down to
* zero, unless the thread is {@linkplain Thread#interrupt interrupted}.
*
* <p>If the current count is zero then this method returns immediately.
*
* <p>If the current count is greater than zero then the current
* thread becomes disabled for thread scheduling purposes and lies
* dormant until one of two things happen:
* <ul>
* <li>The count reaches zero due to invocations of the
* {@link #countDown} method; or
* <li>Some other thread {@linkplain Thread#interrupt interrupts}
* the current thread.
* </ul>
*
* <p>If the current thread:
* <ul>
* <li>has its interrupted status set on entry to this method; or
* <li>is {@linkplain Thread#interrupt interrupted} while waiting,
* </ul>
* then {@link InterruptedException} is thrown and the current thread's
* interrupted status is cleared.
*
* @throws InterruptedException if the current thread is interrupted
*         while waiting
*/
public void await() throws InterruptedException {sync.acquireSharedInterruptibly(1);
}public final void acquireSharedInterruptibly(int arg)throws InterruptedException {if (Thread.interrupted())throw new InterruptedException();if (tryAcquireShared(arg) < 0)doAcquireSharedInterruptibly(arg);
}
  • CountdownLatch的tryAcquireShared方法:如果state==0返回1,否则返回-1;所以只要state不是0,if (tryAcquireShared(arg) < 0)条件就成立,则执行doAcquireSharedInterruptibly方法
protected int tryAcquireShared(int acquires) {return (getState() == 0) ? 1 : -1;
}
  • Aqs的doAcquireSharedInterruptibly方法

用当前线程构造一个共享模式Node,然后CAS操作加入CLH队列尾部,接着仍然是while(true)判断tryAcquireShared(arg),一定要是返回1,才会return,否则就是判断node的前驱节点,然后判断tryAcquireShared(arg)判断

/**
* Acquires in shared interruptible mode.
* @param arg the acquire argument
*/
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) {// 尝试获取资源int r = tryAcquireShared(arg);// 大于等于0,说明有资源获取if (r >= 0) {// 把当前节点设置成head节点,并传播唤醒后面的节点。setHeadAndPropagate(node, r);p.next = null; // help GCfailed = false;return;}}// 这里和独占模式一样,如果没资源申请,封装节点,并park等待if (shouldParkAfterFailedAcquire(p, node) &&parkAndCheckInterrupt())throw new InterruptedException();}} finally {if (failed)cancelAcquire(node);}
}

CyclicBarrier(做加法,例子:召唤神龙,要收集到七龙珠)

A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point. CyclicBarriers are useful in programs involving a fixed sized party of threads that must occasionally wait for each other. The barrier is called cyclic because it can be re-used after the waiting threads are released.

  • cyclic: adj. 循环的; 周期的;
  • barrier: n. 屏障; 障碍物; 障碍; 阻力; 关卡; 分界线; 隔阂;
public class Main {public static void main(String[] args) {CyclicBarrier cyclicBarrier = new CyclicBarrier(7,()->{System.out.println("****召唤神龙****");});for (int i = 1; i <= 7; i++) {final int tempInt = i;new Thread(()->{System.out.println(Thread.currentThread().getName()+"\t收集到第七颗龙珠:"+tempInt+"龙珠");try {cyclicBarrier.await(); // 找到了,就继续等其它龙珠收集} catch (InterruptedException | BrokenBarrierException e) {e.printStackTrace();}}, String.valueOf(i)).start();}}}
http://www.lryc.cn/news/529957.html

相关文章:

  • 力扣动态规划-17【算法学习day.111】
  • 读书笔记-《你的灯亮着吗?》
  • MATLAB实现多种群遗传算法
  • tf.Keras (tf-1.15)使用记录3-model.compile方法
  • Prometheus 中的 Exporter
  • 网工_HDLC协议
  • leetcode 2563. 统计公平数对的数目
  • Debian 10 中 Linux 4.19 内核在 x86_64 架构上对中断嵌套的支持情况
  • FLTK - FLTK1.4.1 - demo - bitmap
  • 数据结构 树1
  • android主题设置为..DarkActionBar.Bridge时自定义DatePicker选中日期颜色
  • MySQL 如何深度分页问题
  • 1.攻防世界easyphp
  • 深度学习 Pytorch 神经网络的学习
  • 如何利用天赋实现最大化的价值输出-补
  • Vue简介
  • three.js+WebGL踩坑经验合集(6.2):负缩放,负定矩阵和行列式的关系(3D版本)
  • 使用 OpenResty 构建高效的动态图片水印代理服务20250127
  • Kafka下载
  • 【C++语言】卡码网语言基础课系列----5. A+B问题VIII
  • IP服务模型
  • 仿真设计|基于51单片机的温湿度、一氧化碳、甲醛检测报警系统
  • QModbusTCPClient 服务器断开引起的程序崩溃
  • Vue 3 30天精进之旅:Day 11 - 状态管理
  • npm 和 pip 安装中常见问题总结
  • Flutter开发环境配置
  • Two Divisors ( Educational Codeforces Round 89 (Rated for Div. 2) )
  • 亚博microros小车-原生ubuntu支持系列:17 gmapping
  • Java面试题2025-并发编程进阶(线程池和并发容器类)
  • Stable Diffusion 3.5 介绍