java 中的 CountDownLatch 有什么意义?

What's the point of CountDownLatch in java?

CountDownLatch in java 是高级同步实用程序,用于防止特定线程开始处理,直到所有线程都准备就绪。

但是,Semaphore完全可以做到同样的事情。那么,CountDownLatch的优点是什么?

还有一个问题:如果CountDownLatch确实有一些优点,为什么它被设计成只使用一次?我认为添加一个设置方法来重置很容易计数。

具有 n 个块的 信号量 达到 0 时。

一个CountDownLatch个块直到达到0。然后全部在大约同一时间继续。

So a semaphore is like a gate keeper at the disco, and a count down latch like a start shot at game courses.

在语义上,它们是不同的;这很重要,因为它使您的代码更易于阅读。当我看到 Semaphore 时,我立即开始思考 "a limited amount of a shared resource." 当我看到 CountDownLatch 时,我立即开始思考 "a bunch of threads waiting for the 'go!' signal." 如果你在实际需要后者的代码中给我前者,那会令人困惑。

从这个意义上讲,信号量用作 CountDownLatch 有点像 garden-path sentence;虽然在技术上是正确的,但它会使人们误入歧途并使他们感到困惑。

就更实用的用途而言,如果您只需要 CountDownLatch,那就更简单了。越简单越好!

至于重复使用 CountDownLatch,这会使它的使用变得复杂。例如,假设您正尝试将线程 A、B 和 C 排队等待某些工作。你让他们等待闩锁,然后你释放它。然后你重置它,大概是为了让线程 D、E 和 F 排队等待其他工作。但是,如果(由于竞争条件)线程 B 尚未真正从第一个闩锁中释放,会发生什么情况?如果它还没有接到 await() 电话怎么办?你是否关闭它的门,并告诉它与 D、E 和 F 一起等待第二次打开?如果第二次打开取决于 B 应该做的工作,那甚至可能导致死锁!

当我第一次阅读 CountDownLatch 时,我也有过关于重置的相同问题。但在实践中,我什至很少想重新设置一个; "wait then go" 的每个单元(A-B-C,然后是 D-E-F)自然地适合创建自己的 CountDownLatch 以配合它,事情保持美好和简单。

Semaphore can totally do the same thing. So, what's the point of CountDownLatch?

Semaphore 维护一组许可证。如果有必要,每个 acquire() 都会阻塞,直到获得许可,然后再拿走它。每个 release() 添加一个许可,可能会释放一个阻塞的获取者。

但是,没有使用实际的许可对象; 信号量只记录可用数量并相应地采取行动

Semaphore阻塞了进入临界区的入口,CountDownLatch阻塞了主线程的执行,除非其他线程完成任务.

查看此 SE 问题了解更多详情:

CountDownLatch vs. Semaphore

If CountDownLatch do have some points, Why It was designed to used only once?

如果要重复使用,就用CyclicBarrier

A synchronization aid that allows a set of threads to all wait for each other to reach a common barrier point. CyclicBarriers are useful in programs involving a fixed sized party of threads that must occasionally wait for each other. The barrier is called cyclic because it can be re-used after the waiting threads are released.

CountDownLatch 的 Javadocs 引用:

CountDownLatch 是一种一次性现象 -- 无法重置计数。 如果您需要重置计数的版本,请考虑使用 CyclicBarrier。