Java并发编程之CountDownLatch闭锁
CountDownLatch
典型应用场景:主线程启动多个子线程同时执行业务逻辑,所有子线程都执行完毕,再唤醒主线程继续执行。
例子:
public class CountDownLatchTest {/*** 计数器,初始为0*/private Integer count = 0;public Integer getCount(){return count;}/*** 执行+1操作*/public void add(){count++;}public static void main(String[] args){CountDownLatchTest test = new CountDownLatchTest();// 线程个数int threadCount = 3;//初始化工作线程的个数,并用CountDownLatch管理CountDownLatch countDownLatch = new CountDownLatch(threadCount);for(int i=0;i<threadCount;i++) {new Thread(() -> {test.add();countDownLatch.countDown();}).start();}try {//等待所有线程执行完毕,在所有线程都执行完毕之前主线程会阻塞countDownLatch.await();} catch (InterruptedException e) {e.printStackTrace();}System.out.println(test.getCount());} }
主线程启动了3个子线程执行add操作,等待3个子线程都执行完毕了,主线程继续执行打印最终的执行结果为:3。
具体实现原理:
public class CountDownLatch {//继承于AQS的同步器private static final class Sync extends AbstractQueuedSynchronizer {private static final long serialVersionUID = 4982264981922014374L;//有参构造函数,count记录了共享资源的个数Sync(int count) {setState(count);}//获取当前共享资源的个数int getCount() {return getState();}/*** 尝试以共享方式获取资源* @return 1表示获取成功,-1表示获取失败*/protected int tryAcquireShared(int acquires) {//如果当前资源个数为0,则表示获取成功,否则表示失败return (getState() == 0) ? 1 : -1;}/*** 尝试以共享方式释放资源* @return true表示释放成功,false表示释放失败*/protected boolean tryReleaseShared(int releases) {// 对当前资源执行-1操作for (;;) {int c = getState();if (c == 0)return false;int nextc = c-1;//CAS更新资源个数,CAS失败表示有其他线程竞争,此时需要重试if (compareAndSetState(c, nextc))//执行-1操作后,如果资源个数为0,则表示释放成功return nextc == 0;}}}private final Sync sync;//有参构造函数,可以看到CountDownLatch中禁用了默认构造函数,意味着必须传入资源个数public CountDownLatch(int count) {if (count < 0) throw new IllegalArgumentException("count < 0");this.sync = new Sync(count);}//等待操作,此方法会使调用线程阻塞,直到其他调用countdown的方法都执行完毕public void await() throws InterruptedException {//此处调用的是AQS的acquireSharedInterruptibly方法,下文会具体分析sync.acquireSharedInterruptibly(1);}//和await()类似,但是有一个等待的超时时间,过了超时时间会自动取消等待public boolean await(long timeout, TimeUnit unit)throws InterruptedException {return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));}//将state的值-1,当getState()==0时,会唤醒调用await()线程public void countDown() {//调用AQS的releaseShared方法,下文会具体分析sync.releaseShared(1);}//获取当前资源的个数public long getCount() {return sync.getCount();} }
CountDownLatch中用到的AQS的核心方法:
public final void acquireSharedInterruptibly(int arg)throws InterruptedException {if (Thread.interrupted())throw new InterruptedException();//尝试获取资源失败(tryAcquireShared的返回值<0),会将当前线程阻塞并排队等待if (tryAcquireShared(arg) < 0)//该方法会将当前线程阻塞,并放入AQS的同步队列等待,此处不再分析doAcquireSharedInterruptibly(arg); }//释放共享资源 public final boolean releaseShared(int arg) {//尝试释放共享资源成功时(此处要结合CountDownLatch提供的tryReleaseShared方法理解),进行具体的释放操作if (tryReleaseShared(arg)) {//AQS提供的执行具体的资源释放操作,会唤醒调用await()方法的线程doReleaseShared();return true;}return false; }
总结:CountDownLatch使用AQS的state变量作为状态计数器,执行countdown操作的线程会将计数器减1,当前计数器的值为0时(getState()==0),会唤醒执行await操作的线程继续执行。
Java并发编程之CountDownLatch闭锁相关推荐
- Java并发编程之CountDownLatch(闭锁)使用详解
package com.zhangxueliang.day_20191108;import java.util.concurrent.CountDownLatch;/*** 计算多线程的运行时间* @ ...
- Java并发编程之CountDownLatch、CyclicBarrier和Semaphore
前言 本文为对CountDownLatch.CyclicBarrier.Semaphore的整理使用 CountDownLatch CountDownLatch类位于java.util.concurr ...
- Java并发编程之CountDownLatch源码解析
一.导语 最近在学习并发编程原理,所以准备整理一下自己学到的知识,先写一篇CountDownLatch的源码分析,之后希望可以慢慢写完整个并发编程. 二.什么是CountDownLatch Count ...
- Java并发编程之CountDownLatch/CyclicBarrierDemo/SemaphoreDemo详解
CountDownLatch详解 什么是CountDownLatch? 代码说明一 :班长锁门 代码说明二:秦国统一六国 什么是CyclicBarrierDemo? 代码说明一:集齐7个龙珠,召唤神龙 ...
- Java并发编程之CountDownLatch
目录 一.概述 二.CountDownLatch与join的异同 三.源码解析 3.1.await方法源码解析 3.2.downCount方法源码解析 一.概述 作用:可以用来确保某些活动直到其他活动 ...
- Java并发编程之CyclicBarrier详解
简介 栅栏类似于闭锁,它能阻塞一组线程直到某个事件的发生.栅栏与闭锁的关键区别在于,所有的线程必须同时到达栅栏位置,才能继续执行.闭锁用于等待事件,而栅栏用于等待其他线程. CyclicBarrier ...
- zbb20180929 thread java并发编程之Condition
java并发编程之Condition 引言 在java中,对于任意一个java对象,它都拥有一组定义在java.lang.Object上监视器方法,包括wait(),wait(long timeout ...
- java并发编程之4——Java锁分解锁分段技术
转载自 java并发编程之4--Java锁分解锁分段技术 并发编程的所有问题,最后都转换成了,"有状态bean"的状态的同步与互斥修改问题.而最后提出的解决"有状态bea ...
- Java 并发编程之美:并发编程高级篇之一-chat
借用 Java 并发编程实践中的话:编写正确的程序并不容易,而编写正常的并发程序就更难了.相比于顺序执行的情况,多线程的线程安全问题是微妙而且出乎意料的,因为在没有进行适当同步的情况下多线程中各个操作 ...
最新文章
- assert self.binded
- 7、ShardingSphere 之 Sharding-Proxy
- 5.3 递归最小二乘法
- 16 张图解带你掌握一致性哈希算法
- 关于Element UI中select组件中遇到的问题
- Android 系统(123)---MTK android 常用修改点
- 数学打比方(函数和卷积)
- c++ string详解 assign
- Doris之拦截规则 sql黑名单
- NYOJ题目325-zb的生日
- config system丢失
- Postgresql去掉某个字段多余的空格
- mysql百万数据迁移_Mysql百万级数据迁移实战笔记
- 机器学习练习----神经网络的标准BP算法(误差逆传播算法)
- MySQL 中文字段排序问题(根据中文拼音排序)
- android浏览器400错误代码,console.log在谷歌浏览器和Android浏览器的本地代码错误...
- Python实现猫脸识别 | 喵主子福利
- Power bi 4.3 子弹图
- 谈IBM的转型与人工智能开发
- ffmpeg多路视频拼接