写点什么

【并发编程】CountDownLatch 详解与原理

  • 2023-12-28
    上海
  • 本文字数:1826 字

    阅读完需:约 6 分钟

【并发编程】CountDownLatch详解与原理

📫作者简介:小明 Java 问道之路2022 年度博客之星全国 TOP3,专注于后端、中间件、计算机底层、架构设计演进与稳定性建设优化,文章内容兼具广度、深度、大厂技术方案,对待技术喜欢推理加验证,就职于知名金融公司后端高级工程师。

           

🏆 2022 博客之星 TOP3 | CSDN 博客专家 | 后端领域优质创作者 | CSDN 内容合伙人

🏆 InfoQ(极客邦)签约作者、阿里云专家 | 签约博主、51CTO 专家 | TOP 红人、华为云享专家

         

 🔥如果此文还不错的话,还请👍关注、点赞、收藏三连支持👍一下博主~ 

​本文导读

本文讲解什么是 CountDownLatch,CountDownLatch 的特点以及使用场景,对 CountDownLatch 的数据结构与 countDown()方法、await()方法源码进行剖析。

一、什么是 CountDownLatch

CountDownLatch 可以使线程顺序执行

CountDownLatch 类在创建实例的时候,需在构造函数中传入倒数次数,然后由需要等待的线程去调用 await 方法开始等待,而每一次其他线程调用了 countDown 方法之后,计数便会减 1,直到减为 0 时,之前等待的线程便会继续运行。

CountDownLatch 不能重用,可以考虑使用 CyclicBarrier 或者创建一个新的 CountDownLatch 实例。

1、CountDownLatch 可以让一个线程等待其他多个线程都执行完毕,再继续自己的工作

public static void main(String[] args) throws InterruptedException {	CountDownLatch latch = new CountDownLatch(5);	ExecutorService service = Executors.newFixedThreadPool(5);	for (int i = 0; i < 5; i++) {		final int no = i + 1;		Runnable runnable = new Runnable() {			@Override			public void run() {				latch.countDown();			}		};		service.submit(runnable);	}
latch.await(); System.out.println("所有线程都执行完");}
复制代码

2、多个线程等待某一个线程的信号,同时开始执行

public static void main(String[] args) throws InterruptedException {	CountDownLatch countDownLatch = new CountDownLatch(1);	ExecutorService service = Executors.newFixedThreadPool(5);	for (int i = 0; i < 5; i++) {		final int no = i + 1;		Runnable runnable = new Runnable() {			@Override			public void run() {				countDownLatch.await();			}		};		service.submit(runnable);	}
System.out.println("执行开始!"); countDownLatch.countDown();}
复制代码

二、CountDownLatch 实现原理

1、CountDownLatch 数据结构

CountDownLatch 是利用 AQS 共享锁机制的同步器 Sync 来实现的

public class CountDownLatch {    // 继承AQS来实现同步器,    private static final class Sync extends AbstractQueuedSynchronizer {			// 通过state控制count        Sync(int count) {            setState(count);        }
// 重写AQS的tryAcquireShared,通过获取共享锁的方式实现等待 protected int tryAcquireShared(int acquires) { // 当state不为0时一直阻塞 return (getState() == 0) ? 1 : -1; }
// 释放共享锁 protected boolean tryReleaseShared(int releases) { for (;;) { int c = getState(); // 如果state为0,则不能再使用, if (c == 0) return false; // state减1 int nextc = c-1; // 为0,释放共享锁,唤醒等待线程 if (compareAndSetState(c, nextc)) return nextc == 0; } } }
// 同步器变量 private final Sync sync; // 创建同步器,设置AQS的state变量为1 public CountDownLatch(int count) { if (count < 0) throw new IllegalArgumentException("count < 0"); this.sync = new Sync(count); }}
复制代码

2、countDown() 方法

// 直接调用AQS的releaseShared,释放共享锁,从而回调tryAcquireSharedpublic void countDown() {    sync.releaseShared(1);}
复制代码

3、await() 方法

public void await() throws InterruptedException {    // 调用AQSacquireSharedInterruptibly,释放共享锁    sync.acquireSharedInterruptibly(1);}
复制代码

总结

本文讲解什么是 CountDownLatch,CountDownLatch 的特点以及使用场景,对 CountDownLatch 的数据结构与 countDown()方法、await()方法源码进行剖析。

发布于: 刚刚阅读数: 3
用户头像

InfoQ签约作者/技术专家/博客专家 2020-03-20 加入

🏆InfoQ签约作者、CSDN专家博主/后端领域优质创作者、阿里云专家/签约博主、华为云专家、51CTO专家/TOP红人 📫就职某大型金融互联网公司高级工程师 👍专注于研究Liunx内核、Java、源码、架构、设计模式、算法

评论

发布
暂无评论
【并发编程】CountDownLatch详解与原理_并发编程_小明Java问道之路_InfoQ写作社区