前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >CountDownLatch 核心源码解析

CountDownLatch 核心源码解析

作者头像
JavaEdge
发布2020-05-27 10:53:28
3090
发布2020-05-27 10:53:28
举报
文章被收录于专栏:JavaEdgeJavaEdgeJavaEdge

1 基本设计

一种同步辅助,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。 CountDownLatch 是用给定的 count 初始化的。由于调用了countDown()方法,await 方法阻塞,直到当前计数为零,之后释放所有等待线程,并立即返回任何后续的 await 调用。这是一种一次性现象——计数无法重置。如果需要重置计数的版本,可以考虑使用CyclicBarrier

CountDownLatch 是一种通用的同步工具,可以用于多种用途。count为1时初始化的CountDownLatch用作简单的 on/off 的 latch或gate:所有调用wait的线程都在gate处等待,直到调用countDown()的线程打开它。一个初始化为N的CountDownLatch可以用来让一个线程等待,直到N个线程完成某个动作,或者某个动作已经完成N次。

CountDownLatch的一个有用的特性是,它不需要调用倒计时的线程等待计数达到0才继续,它只是防止任何线程继续等待,直到所有线程都通过。

2 类架构

2.1 UML 图

2.2 继承关系

可以看出,CountDownLatch并无显式地继承什么接口或类。

2.3 构造函数细节

  • 构造一个用给定计数初始化的CountDownLatch。
  • 参数 count 在线程通过await()之前必须调用countDown()的次数

CountDownLatch 的 state 并不是 AQS 的默认值 0,而是可赋值的,就是在 CountDownLatch 初始化时,count 就代表了 state 的初始化值

  • new Sync(count) 其实就是调用了内部类 Sync 的如下构造函数

count 表示我们希望等待的线程数,可能是

  • 等待一组线程全部启动完成,或者
  • 等待一组线程全部执行完成

2.4 内部类

和 ReentrantLock 一样,CountDownLatch类也存在一个内部同步器 Sync,继承了 AbstractQueuedSynchronizer

  • 这也是唯一的属性

  
  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) {
  // 降低计数器; 至 0 时发出信号
  for (;;) {
  // 获取锁状态
  int c = getState();
  // 锁未被任何线程持有
  if (c == 0)
  return false;
  int nextc = c-1;
  if (compareAndSetState(c, nextc))
  return nextc == 0;
  }
  }
 }
  

3 await

可以叫做等待,也可以称之为加锁。

3.1 无参

造成当前线程等待,直到锁存器计数到零,除非线程被中断。 如果当前计数为零,则此方法立即返回。

如果当前线程数大于0,则当前线程将出于线程调度的目的而禁用,并处于睡眠状态,直到发生以下两种情况之一:

  • 由于调用了countDown()方法,计数为零
  • 其他线程中断了当前线程

如果当前线程:

  • 在进入此方法时已设置其中断状态;或者
  • 在等待时被中断

就会抛 InterruptedException,并清除当前线程的中断状态。

无参版 await 内部使用的是 acquireSharedInterruptibly 方法,实现在 AQS 中的 final 方法

  1. 使用CountDownLatch 的内部类 Sync 重写的tryAcquireShared 方法尝试获得锁,如果获取了锁直接返回,获取不到锁走 2
  2. 获取不到锁,用 Node 封装一下当前线程,追加到同步队列的尾部,等待在合适的时机去获得锁,本步已完全实现在 AQS 中

tryAcquireShared

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-02-27 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 基本设计
  • 2 类架构
    • 2.1 UML 图
      • 2.2 继承关系
        • 2.3 构造函数细节
          • 2.4 内部类
          • 3 await
            • 3.1 无参
              • tryAcquireShared
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档