たCountDownLatchてAQSスヌープ

公共号「カフナ」、検索可能Alitaba119、歓迎の注意からこの記事では、どうもありがとうございました、ソースを明記してください


 まで、1つ以上のスレッドを待機することを可能にする同期補助  操作のセットが他のスレッドで実行されるが完了する。

ように、シンクロナイザの実現:これは解決すべきたCountDownLatchクラスの問題である一件の以上のスレッドが完了するために、他のスレッドで実行された操作のセットまで待機します。


ディレクトリ

、たCountDownLatchクラスのワークフロー

二、たCountDownLatchクラスの使用法

三、たCountDownLatchクラスは、ソースコードを解析し、

第四に、思考ポイントたCountDownLatchクラス

五、アプリケーションシナリオのたCountDownLatchクラス

第六に、記事のスパイAQS質問はReentrantLockの通過答え

七、AQSシリーズが推奨


、たCountDownLatchクラスの使用法

我々のテストコードを見て、waitThread1とwaitThread2 2つのスレッドがラッチ待って、latch.countDown()に別の5つのタスクの実行スレッドは、タスク・レディな最後のタスクの実行として、(今回はタスクスレッドが背後にあるロジックを実行していきます) waitThread1(後)latch.countDown、waitThread2は継続目覚めます。

この図は、二回の結果です:


タスクスレッドのカウントダウンを実行し、別の実行waitThread1とwaitThread2と固定されないための5つのタスク・スレッド、結果が出図から分かるように、waitThread1とwaitThread2 2つのスレッドが準備した後、実行を継続する前に5つのタスクスレッドを待ちます後の()メソッドは、背後にあるロジックを実行していきます。

二、たCountDownLatchクラスのワークフロー

通过下面这个动图来展示CountDownLatch的整个工作流程,需要注意的是等待线程和任务线程的区别,另外在任务就绪之后,整个释放的流程需要重点关注,共享节点的释放并不是固定一个个节点按顺序释放的,而是可能多个节点同时释放的。


三、CountDownLatch类源码解析

CountDownLatch源码相对来说还是比较简单的,最核心的就是理解他的工作步骤以及同步器的实现。
工作步骤:

  • 初始化的时候定义几个任务,即同步器中state的数量
  • 等待线程执行await方法等待state变成0,等待线程会进入同步器的等待队列
  • 任务线程执行countDown方法之后,state值减1,直到减到0,唤醒等待队列中所有的等待线程。

同步器实现了tryAcquireShared方法,判断当state!=0的时候把等待线程加入到等待队列并阻塞等待线程,state=0的时候这个latch就不能够再向等待队列添加等待线程;另外实现了tryReleaseShared,判断当前任务是否是最后一个任务,当state减到0的时候就是最后一个任务,然后会以传播唤醒的方式唤醒等待队列中的所有等待线程。


四、CountDownLatch类的思考点

这边的思考点只有一个,latch任务线程都就绪之后怎么释放?要了解这个点,我们需要具体看下AQS中的doReleaseShared方法。

不知道大家有没有想过,上图1,2,3处代码,作者为什么要这么写?

在解释这三处代码之前,我们首先要弄清楚SHARD节点的释放方式。

假如我们有以下的共享节点组成的AQS等待队列:

主线程调用doReleaseShared方法,进入for循环自旋,head节点的地址赋值给h,然后判断是否有后继节点并需要释放,最后判断h中的地址和当前的head节点的地址是否一样,如果一样,则退出for循环,流程图如下:

每一个被唤醒的线程都会进入自旋逻辑,而且每个线程都有一个head地址的本地变量副本,当这个副本和当前的head节点的地址不一致的时候,会继续自旋, 获取最新的head节点,去尝试唤醒下一个线程。我们看下下面的这几种时序:

第一处代码为什么需要把waitStatus设置成0?
如果waitStatus=NODE.SIGNAL,不把状态设置成0,则自旋的时候有可能重复触发唤醒同一个节点(上图中如果主线程,t1线程,t2线程自旋的时候,head指向线程t3节点,waitStatus如果等于-1,则线程t4就会被重复唤醒)。

第二处代码:为什么等于0的时候要设置NODE.PROPAGATE?
还是拿上面的case举例子,假如现在head指向线程t4,如果主线程,t1线程,t2线程,t3线程同时完成自己的唤醒任务,然后都获取了线程t4的head地址,第一个线程把线程t4节点的waitStatus改成了0,那后面的线程会尝试把0改成PROPAGATE(这里过来的线程有两种可能,修改waitStatus从-1到0失败继续自旋过来,或者是判断waitStatus=0过来),如果不成功,则自旋,如果成功则判断head是否有变化,简单的说就是让竞争修改waitStatus为PROPAGATE失败的线程继续释放其他的节点。

第三处代码:为什么要设置h==head退出自旋?

最主要的原因是,不然我怎么跳出自旋呢!另外如果head不一致,当前线程可以帮忙一起释放剩余的等待线程,提高释放效率。


五、CountDownLatch类的适用场景

如果你要执行一个任务,但是必须先等其他几个任务做到某个程度这个任务才能够启动,这个时候就比较适合用CountDownLatch。但是一般会使用超时等待的方式来处理,不然如果其中某个任务异常没有完成,或者超时了,那么任务会一直等待在那里。


六、文章透过ReentrantLock窥探AQS问题回答

目前ReentrantLock窥探AQS文章还没收集到问题,有兴趣的同学可以点进去看看,在文章下留言就行


七、AQS系列推荐

“ 本系列文章旨在对并发包中的AQS以及跟AQS相关的锁做一个深入的讲解,让各位看官可以深入理解AQS以及对应的锁”

透过ReentrantLock窥探AQS

透过CountDownLatch窥探AQS

AQS条件队列和同步队列的关系

透过ReentrantReadWriteLock窥探AQS

通过Semaphore窥探AQS

 


尾声


tips:文章中的部分图片是传到微博上再导过来的(微信文章中的不能直接用),有点糊,如果想要高清的图片可以关注我的公众号Alitaba119,公众号文章中的图片比较清楚。

如果本文章解决了各位看官心里的一些疑惑,可以关注本公众号,后续会有更多精彩文章,也可以帮忙推荐给其他的小伙伴,让更多的人受益,万分感谢。

如果看了文章之后心中还有疑惑,请在文章下面留言,下一篇文章「AQS条件队列和同步队列的关系」中我会对前一篇文章大家的问题做一个解答。

おすすめ

転載: www.cnblogs.com/God-froest/p/CountDownLatch.html