CountDownLatch
是一个高级同步实用程序,用于防止特定线程在所有线程准备就绪之前开始处理。
但是,Semaphore
完全可以做同样的事情。那么, CountDownLatch
的优点是什么?
还有一个问题:如果CountDownLatch
确实有一些优点,为什么它只设计为使用一次?我认为添加set方法来重置计数很容易。
答案 0 :(得分:5)
从语义上讲,它们是不同的;这很重要,因为它使您的代码更容易阅读。当我看到一个信号量时,我立即开始思考“有限数量的共享资源”。当我看到一个CountDownLatch时,我立即开始思考“一堆线程等着'去!'信号。”如果你在代码中给我前者实际上需要后者,那就太麻烦了。
从这个意义上讲,用作CountDownLatch的信号量有点像garden-path sentence;虽然技术上是正确的,但它会让人误入歧途并使他们感到困惑。
就更实用的用法而言,只要你需要,CountDownLatch就更简单了。越简单越好!
至于重用CountDownLatch,会使其使用复杂化。例如,假设您正在尝试将线程A,B和C排队等待某些工作。你让他们等待闩锁,然后你释放它。然后你重置它,大概是为了其他一些工作排队线程D,E和F.但是如果(由于竞争条件),线程B实际上还没有从第一个锁存器释放,会发生什么呢?如果它还没有接到await()
电话怎么办?你是否关闭了门,并告诉它等待D,E和F进行第二次打开?如果第二次打开取决于B应该做的工作,那甚至可能导致死锁!
当我第一次阅读有关CountDownLatch的内容时,我遇到了与重置相同的问题。但实际上,我很少想重置一个; “等待然后去”(A-B-C,然后是D-E-F)的每个单元自然有助于创建自己的CountDownLatch以与它一起使用,并且事情保持美观和简单。
答案 1 :(得分:4)
信号量,当 0到达时,n块
。到达 0的n个块的 CountDownLatch 。然后所有人都在大约同一时间继续。
因此,信号量就像是迪斯科舞厅的守门员,倒计时闩锁就像游戏课程的开始一样。
答案 2 :(得分:1)
信号量完全可以做同样的事情。那么,CountDownLatch的重点是什么?
Semaphore
维持一组许可。如果需要,每个acquire()
阻止,直到有许可证,然后接受。每个release()
都会添加一个许可证,可能会释放阻止收购者。
但是,没有使用实际的许可对象; 信号量只保留可用数量的计数并相应地采取行动。
Semaphore
阻止进入关键部分的条目,CountDownLatch
阻止主线程的执行,除非其他线程完成其任务 。
有关详细信息,请查看此SE问题:
如果CountDownLatch确实有一些点,为什么它只被设计为使用一次?
如果要重复使用,请使用CyclicBarrier
一种同步辅助工具,允许一组线程全部等待彼此到达公共障碍点。 CyclicBarriers在涉及固定大小的线程方的程序中很有用,这些线程必须偶尔等待彼此。屏障称为循环,因为它可以在等待线程释放后重新使用。
CountDownLatch的Javadocs引用:
CountDownLatch是一次性现象 - 计数无法重置。 如果您需要重置计数的版本,请考虑使用CyclicBarrier。