关注我们
QRcode 邮件联系 新浪微博
首页 > 中医健康 » 正文

Java编发编程中CountDownLatch到底是个啥?

   条点评
后台-系统设置-扩展变量-手机广告位-内容正文顶部

文章篇幅较短,对于一些AQS的顶级方法例如releaseShared并没有做过深的讲解,因为这些算是AQS的范畴。

CountDownLatch一般被称作"计数器",作用大致就是数量达到了某个点之后计数结束,才能继续往下走。可以用作流程控制之类的作用,大流程分成多个子流程,然后大流程在子流程全部结束之前不动(子流程最好是相互独立的,除非能很好的控制两个流程的关联关系),子流程全部结束后大流程开始操作。

很抽象,小问题,下方的两节或许能让你理解CountDownLatch的用法和内部的实现。

1.CountDownLatch的使用

假设现在,我们要起一个3块钱的集资项目,并且限定每个人一次只能捐1块钱当募集到3块钱的时候立马就把这笔钱捐给我自己,如果凑齐之后你还想捐,那么我会跟你说,项目已经完成了,你这一块钱我不受理,自己去买雪糕吃吧;如果没凑齐,那么我这个募集箱就一直挂在这里。这个场景用CountDownLatch可以很契合的模拟出来。

字数也不凑了,直接看demo例子吧

结果图:

这个结果,em,可以看到countDownLatch使用的几个注意点:

调用countDownLatch的await()方法的线程会阻塞,直到凑够3块钱为止跟CyclicBarrier不同,其计完数之后并不会阻塞,而是直接执行接下来的操作每次调用countDown()方法都会捐一块钱(计数一次),满了之后调用await()方法的线程不再阻塞另外,在上面的代码中,在countDown方法之后还打印信息是为了验证countDown方法不会阻塞当前线程,执行结果不一定如上图那样有顺序的,例如可能出现下方的结果

因为最后一个countDown之后,await所在的线程不再阻塞了,又正好赶上JVM线程调度,所以就会出现上方的结果。

2.CountDownLatch的内部实现

刚才已经讲了CountDownLatch的用法,用起来还是不难的。那来看下内部是怎么实现的,又是怎么做到计数之后不跟CyclicBarrier一样阻塞的呢?

首先来看构造函数吧,CountDownLatch只有一个构造函数,如下

所做的事情也就只有初始化内部对象sync一件事情(校验总不能算一件事吧?),那来看下初始化了个啥玩意

既然涉及到了AQS,那你应该懂我意思了——快去看我写的AQS文章啊。

开个玩笑,我知道各位都多多少少了解一些,上方代码的作用应该知道是干嘛的,不懂也没关系,等下我在下面再讲。

回到正题,来讲下从上方代码能得到什么信息

1.CountDownLatch构造函数count的参数作用就是设置其内部的AQS的状态state,假设count为3,那么每次进行countDown,AQS的state就减1,减到0的时候await方法就不再阻塞,注意这时候await方法就不再阻塞了,无论你调多少次。2.CountDownLatch里边的Sync实现的AQS的共享模式(从tryReleaseShared方法可以看出)

到这里对其CountDownLatch的内部有个差不多印象了,接下来看下其最重要的await和countDown方法。

2.1 await方法

直接调用了AQS的顶级方法,再进去就是AQS的模块了

简单说明一下,这个方法的意思就是调用tryAcquireShared的方法尝试获取资源,方法返回负数表示失败,返回正数则表示成功;失败了则入同步队列(即阻塞),具体的细节可以看下AQS的详解。

也就是说关键点是tryAcquireShared方法,这个方法刚才在上方已经解释过,这里再放一次。方法逻辑很简单,如果state=0(即计数完毕)则成功,否则失败。

okay,await方法的整个流程大致就是:尝试获取资源,如果失败则阻塞,成功了继续当前线程的操作。什么时候会失败呢,在state!=0的时候,而state这个变量的值我们在构造函数就已经赋予了,需要通过countDown方法来减少。

2.2 countDown

既然这个方法这么重要,那让它开始它的表演吧。

同样的,直接调用AQS的顶级释放资源的方法。

关键的方法还是在资源的控制上——tryReleaseShared,代码如下(上方也有):

到这里countDown方法的迷雾也看清了,每一次调用countDown方法就相当于调用tryReleaseShared方法,如果当前资源还没释放的话,将state-1,判断是否为0,如果为0的话表示资源释放,唤醒await方法的线程,否则的话只是更新state的值。

整理一下整个CountDownLatch的流程。

1.创建一个CountDownLatch,并赋予一个数值,这个值表示需要计数的次数,每次countDown算一次2.在主线程调用await方法,表示需要计数器完成之前都不能动。await方法的内部实现依赖于内部的AQS,调用await方法的时候会尝试去获取资源,成功条件是state=0,也就是说除非countDown了count(构造函数赋予)次之后,才能成功,失败的话当前线程进行休眠。3.在子线程调用countDown方法,每次调用都会使内部的state-1,state为0的时候资源释放,await方法不再阻塞(即使再次调用也是)

3. 小结

如果理解AQS的话,不止CountDownLatch,其他衍生物例如ReentrantLock都能轻易的看懂。如果不了解的话也没关系,这篇文章应该能让你对CountDownLatch的内部实现有了大概的轮廓。

简单总结一下,CountDownLatch就三个点:构造函数的值、await、countDown。构造函数的值表示计数的次数,每次countDown都会使计数减一,减到0的时候await方法所在的线程就不再阻塞。

后台-系统设置-扩展变量-手机广告位-内容正文底部
[迷瘦雪盈套盒怎么拿货]迷瘦雪盈套盒怎么拿货|
非我市场需求量大吗?非我套装怎么样?怎么拿货便宜些?--伦娜综合门户网

已有条评论,欢迎点评!