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

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

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

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

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

本文目录

本文导读

一、什么是CountDownLatch

二、CountDownLatch实现原理

1、CountDownLatch数据结构

2、countDown() 方法

3、await() 方法

总结

本文导读

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

一、什么是CountDownLatch

CountDownLatch可以使线程顺序执行

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

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

1、CountDownLatch可以让一个线程等待其他多个线程都执行完毕,再继续自己的工作
ini 复制代码
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、多个线程等待某一个线程的信号,同时开始执行

ini 复制代码
 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来实现的

java 复制代码
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() 方法

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

3、await() 方法

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

总结

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

相关推荐
幸好我会魔法2 小时前
人格分裂(交互问答)-小白想懂Elasticsearch
大数据·spring boot·后端·elasticsearch·搜索引擎·全文检索
SomeB1oody2 小时前
【Rust自学】15.2. Deref trait Pt.1:什么是Deref、解引用运算符*与实现Deref trait
开发语言·后端·rust
何中应3 小时前
从管道符到Java编程
java·spring boot·后端
组合缺一3 小时前
Solon Cloud Gateway 开发:Route 的过滤器与定制
java·后端·gateway·reactor·solon
SomeB1oody3 小时前
【Rust自学】15.4. Drop trait:告别手动清理,释放即安全
开发语言·后端·rust
customer084 小时前
【开源免费】基于SpringBoot+Vue.JS贸易行业crm系统(JAVA毕业设计)
java·vue.js·spring boot·后端·spring cloud·开源
花心蝴蝶.5 小时前
Spring IoC & DI
java·后端·spring
半夏知半秋6 小时前
rust学习-所有权
开发语言·后端·学习·rust
Ciderw6 小时前
TCP三次握手和四次挥手
开发语言·网络·c++·后端·网络协议·tcp/ip·golang
长路 ㅤ   7 小时前
SpringBoot支持动态更新配置文件参数
java·spring boot·后端·动态配置