功能描述

  一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。

  常见用法

  多个人等一个信号后继续执行操作。例如5个运动员,等一个发令员的枪响。

  一个人等多个人的信号。旅游团等所有人签到完成才开始出发。

  我们最常见见到使用的地方是zk获取连接的时候

  final CountDownLatch countDownLatch=new CountDownLatch(1);

  ZooKeeper zooKeeper=new ZooKeeper(zk_url, time_out, new Watcher() {

  public void process(WatchedEvent watchedEvent) {

  Event.KeeperState state = watchedEvent.getState();

  Event.EventType type = watchedEvent.getType();

  if(Event.KeeperState.SyncConnected==state){

  if(Event.EventType.None==type){

  //调用此方法测计数减一

  countDownLatch.countDown();

  }

  }

  }

  });

  //阻碍当前线程进行,除非计数归零

  countDownLatch.await();

  这里了也可以看到很明确的使用方法,countDown直到0,await的线程才会继续执行。

  原理

  CountDownLatch内部使用了共享锁。如果这里还不知道共享和独占的区别,可以看前面的aqs速读。

  获取锁成功的方法很简单

  protected int tryAcquireShared(int acquires) {

  return (getState() == 0) ? 1 : -1;

  }

  共享锁有个约定,返回有三种情况。

  0为获取锁且没有其他资源

  正数 获取锁并且还有其他资源

  负数 获取锁资源失败

  共享锁在tryAcquireShared返回大于0的值的时候,会唤醒其他停顿状态加锁线程。由于没有对state的增加操作,所以当state变成0的时候,所有尝试加锁的线程都会被唤醒。

  protected boolean tryReleaseShared(int releases) {

  // Decrement count; signal when transition to zero

  for (;;) {

  int c = getState();

  if (c == 0)

  return false;

  int nextc = c-1;

  if (compareAndSetState(c, nextc))

  return nextc == 0;

  }

  }

  释放锁的操作,就是把state的值减一,当只有state变成0的时候,才返回true,tryReleaseShared返回true的时候会触发唤醒其他加锁线程的操作。

  通过上面的过程,我们可以看到CountDownLatch中的共享锁的加锁和释放锁的过程,下面看看是如何和CountDownLatch结合的。

  public CountDownLatch(int count) {

  if (count 0) throw new IllegalArgumentException(count 0);

  this.sync = new Sync(count);

  }

  CountDownLatch的构造里会初始化共享锁,并且设置state的值。

  public void countDown() {

  sync.releaseShared(1);

  }

  countDown是释放锁,最终会调用到tryReleaseShared。

  public void await() throws InterruptedException {

  sync.acquireSharedInterruptibly(1);

  }

  await是加锁,最终会调用到 tryAcquireShared。

  CountDownLatch就是一个不断释放锁的过程。

  常见问题

  CountDownLatch是不能够重用的

  根据上面的解析,大家也发现,共享锁加锁的操作并不会增加state的值。CountDownLatch中state一旦变成0就没有提供其他方式增长回去了。

  所以CountDownLatch是一次性消耗品,用完就得换新的。这样设计也是比较正常的,对状态的要求比较严格,例如都开车了你再告诉司机,这次加了5个人,车都开了一半了,不会考虑再回去。随意修改约束值会带来很多逻辑上的问题。

  CountDownLatch无限等待

  countDown没有被调用,那么await就会一直等下去。countDown常见没有被调用的情况:异常中断,线程池拒绝策略。

  可以使用

  public boolean await(long timeout, TimeUnit unit)

  根据业务情况,增加一个最大等待时间。使用这种方式,需要对失败的各种情况作出业务上的对应处理,否则就出现各种数据不正确的问题。也可以对countDown的线程做好异常处理,最好使用另外一个线程池来处理这些线程。这种情况就需要对业务不能停顿时间特别长,导致线程池的资源被耗光的情况做处理。如果是想通过new Thread避免,就需要考虑线程突然暴涨的问题。

CountDownLatch详解的更多相关文章

  1. 最强Java并发编程详解:知识点梳理,BAT面试题等

    本文原创更多内容可以参考: Java 全栈知识体系.如需转载请说明原处. 知识体系系统性梳理 Java 并发之基础 A. Java进阶 - Java 并发之基础:首先全局的了解并发的知识体系,同时了解 ...

  2. AQS详解

    一.概述 谈到并发,不得不谈ReentrantLock:而谈到ReentrantLock,不得不谈AbstractQueuedSynchronized(AQS)! 类如其名,抽象的队列式的同步器,AQ ...

  3. Java并发之AQS详解

    一.概述 谈到并发,不得不谈ReentrantLock:而谈到ReentrantLock,不得不谈AbstractQueuedSynchronizer(AQS)! 类如其名,抽象的队列式的同步器,AQ ...

  4. java并发包java.util.concurrent详解

    线程池ThreadPoolExecutor的使用 并发容器之CopyOnWriteArrayList 并发容器之CopyOnWriteArraySet 数据结构之ConcurrentHashMap,区 ...

  5. (转)Java并发包基石-AQS详解

    背景:之前在研究多线程的时候,模模糊糊知道AQS这个东西,但是对于其内部是如何实现,以及具体应用不是很理解,还自认为多线程已经学习的很到位了,贻笑大方. Java并发包基石-AQS详解Java并发包( ...

  6. 【1】AQS详解

    概述: 它内部实现主要是状态变量state和一个FIFO队列来完成,同步队列的头结点是当前获取到同步状态的结点,获取同步状态state失败的线程,会被构造成一个结点加入到同步队列尾部(采用自旋CAS来 ...

  7. Zookeeper客户端Curator使用详解

    Zookeeper客户端Curator使用详解 前提 最近刚好用到了zookeeper,做了一个基于SpringBoot.Curator.Bootstrap写了一个可视化的Web应用: zookeep ...

  8. Java性能分析之线程栈详解与性能分析

    Java性能分析之线程栈详解 Java性能分析迈不过去的一个关键点是线程栈,新的性能班级也讲到了JVM这一块,所以本篇文章对线程栈进行基础知识普及以及如何对线程栈进行性能分析. 基本概念 线程堆栈也称 ...

  9. Java并发之AQS详解(转)

    一.概述 谈到并发,不得不谈ReentrantLock:而谈到ReentrantLock,不得不谈AbstractQueuedSynchronized(AQS)! 类如其名,抽象的队列式的同步器,AQ ...

随机推荐

  1. cordova 入门

    1. npm install -g cordova On Windows, npm can usually be found at C:\Users\username\AppData\Roaming\ ...

  2. Java-工程中常用的程序片段

    1.字符串-整型相互转换 String s = String.valueOf(2); int a = Integer.parseInt(s); 2.向文件末尾添加内容 BufferedWriter b ...

  3. JavaScript闭包和this绑定

    本文最主要讲讲JavaScript闭包和this绑定相关的我的小发现,鉴于这方面的基础知识已经有很多很好的文章讲过了,所以基本的就不讲了,推荐看看[酷壳](http://coolshell.cn/)上 ...

  4. 前台js加密实例

    1.base64加密 一个字节一般由8位表示,base64加密就是把8位表示转为6为表示,余下2位添0表示,故有个特点不能充分利用空间. 资源下载:jquery.js,base64.js // `ut ...

  5. Java中的反射[转载]

    转自:https://blog.csdn.net/sinat_38259539/article/details/71799078#commentBox 1.什么是反射? 反射是通过一个类可以知道其中所 ...

  6. 数据结构-平衡二叉树 旋转过程平衡因子分析 c和java代码实现对比

    平衡二叉搜索树(Self-balancing binary search tree)又被称为AVL树(有别于AVL算法),且具有以下性质:它是一 棵空树或它的左右两个子树的高度差的绝对值不超过1,并且 ...

  7. one hot coding -机器学习

    机器学习 数据预处理之独热编码(One-Hot Encoding) 问题由来 在很多机器学习任务中,特征并不总是连续值,而有可能是分类值. 例如,考虑一下的三个特征: ["male" ...

  8. [golang note] 变量常量

    变量 • 变量声明 √ golang变量声明的关键字为var. √ golang变量声明时类型信息放置在变量名之后. ▶ 单个变量声明 ▪ 语法如下 var name type ▪ 示例如下 var ...

  9. mysql相关配置

    http://www.cnblogs.com/cnblogsfans/archive/2009/09/21/1570942.html http://www.jb51.net/article/31902 ...

  10. jar打包方法使用整理

    dos窗口下操作jar:(JDK的命令) jar命令能够把Java应用打包成一个文件,这个文件的扩展名为.jar,称为JAR文件.JAR 文件非常类似 ZIP 文件.准确的说,它就是 ZIP 文件,所 ...