生活资讯
countdownlatch 、countdownlatchawait
2023-04-11 00:30  浏览:46

CountDownLatch详解

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

常见用法

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

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

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

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

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

获取锁成功的方法很简单

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

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

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

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

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

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

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

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

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

同步工具类—CountDownLatch详解

CountDownLatch 是JDK并发包中提供的一个同步工具类。官方文档对这个同步工具的介绍是:

上面的英文介绍大致意思是: CountDownLatch 的主要功能是让一个或者多个线程等待直到一组在其他线程中执行的操作完成。

观看上面的解释可能并不能直观地说明 CountDownLatch 的作用,下面我们通过一个简单的列子看下 CountDownLatch 的使用。

场景:主人(主线程)请客人(子线程)吃晚饭,需要等待所有客人都到了之后才开饭。我们用 CountDownLatch 来模拟下这个场景。

上面的列子中,主人(master线程)请了5个客人吃饭,每个客人到了之后会将 CountDownLatch 的值减一,主人(master)会一直等待所有客人到来,最后输出”开饭“。

CountDownLatch 的使用方式很简单,下面来看下它的实现原理。

首先我们先看下 CountDownLatch 重要的API

下面我们看下具体API的源代码

在构建 CountDownLatch 对象时需要传入一个int型的初始值,这个值就是计数器的初始值。从上面的代码中可以看出,创建 CountDownLatch 是new了一个 Sync 对象。

Sync对象是基于AQS机制实现的,自己实现了 tryAcquireShared 和 tryReleaseShared 方法。

调用 await 方法其实是调用了AQS的 acquireSharedInterruptibly 方法。

在 acquireSharedInterruptibly 中先判断了下当前线程有没有被中断,假如线程已经被中断了,直接抛出中断异常。否则进入 doAcquireSharedInterruptibly 。

doAcquireSharedInterruptibly的处理逻辑是先判断队列中是否只有当前线程,如果只有当前线程的先尝试获取下资源,如果获取资源成功就直接返回了。获取资源不成功就判断下是否要park当前线程,如果需要park当前线程,

那么当前线程就进入waiting状态。否则在for循环中一直执行上面的逻辑。

熟悉AQS机制的会知道上面的代码其实也是调的AQS的 releaseShared 。 releaseShared 的方法会调到 Sync 中的 tryReleaseShared 。

上面的代码逻辑很简单:status的值是0的话就返回true,否则返回false。返回true的话,就会唤醒AQS队列中 所有 阻塞的线程。

countdownlatch 导致的多线程死锁

countdownlatch是通过计数器实现的,初始化时定义count数,每一个线程执行完将count数-1.当count=0时表示所以线程执行完毕,可以进入接下来的逻辑。

countdownlatch的await()方法是等待count=0,执行此方法时,执行完的线程会进入阻塞,并等待其他线程完成,当所有线程完成时,await会唤醒阻塞队列并释放所有线程资源。

当高并发请求时,countdownlatch的await方法有可能会引起死锁。如果使用的线程池数量较少,在高并发时会出现多个请求占用了全部的线程资源,但是每个请求又需要await其他线程,其他线程在等待线程池资源,导致多个请求同时进入线程阻塞,最后形成死锁。

解决方法,使用自定义线程池,扩大线程数量,并且建立线程池拒绝机制。

countdownlatch的介绍就聊到这里吧,感谢你花时间阅读本站内容,更多关于countdownlatchawait、countdownlatch的信息别忘了在本站进行查找喔。

发表评论
0评