我正在阅读多线程,并遇到了这两个多线程概念,我已经了解它们的区别以及应该在什么情况下使用它们,但我不明白为什么Java有两个类可以完成同样的工作?
CyclicBarrier
可以做CountDownLatch
的所有事情,那么为什么CountDownLatch
会出现在Java标准库中呢?
我正在阅读多线程,并遇到了这两个多线程概念,我已经了解它们的区别以及应该在什么情况下使用它们,但我不明白为什么Java有两个类可以完成同样的工作?
CyclicBarrier
可以做CountDownLatch
的所有事情,那么为什么CountDownLatch
会出现在Java标准库中呢?
一个简短、不过于详细的答案...首先附上它们各自的Javadoc链接:
简而言之,主要区别在于,与CyclicBarrier
不同的是,一旦CountDownLatch
完成且结束,它就不能被重复使用。Javadoc明确提到了这一点:
这是一个一次性现象 -- 计数无法被重置。如果需要一个可以重置计数的版本,请考虑使用CyclicBarrier。
确实如此,我们发现CyclicBarrier
有一个名为.reset()
的方法,它做了它的意思。不仅如此,还有一个构造函数的版本将一个Runnable关联到每次触发障碍时运行(这就是Javadoc所说的,别问我)。
因此,它们确实不同,简单地说,一个是可重用的(CyclicBarrier
),而另一个是不可重用的(CountDownLatch
)。
CountDownLatch
;你可以重复使用 CyclicBarrier
。不,一个不能代替另一个。 - fgeCountDownLatch
的实现针对这种一次性场景进行了优化。正如我所说,我给出的答案并不是非常详细,因此您可能希望 完全阅读 每个 javadoc,以了解为什么要使用其中一个而不是另一个。 - fge// thread 1
for (int i = 0; i < 10; i++) {
latch.countDown() //perfectly fine
}
//thread 2
for (int i = 0; i < 10; i++) {
barrier.await() //oops
}
CountDownLatch
和Semaphore
。基本上您可以用其中一个替换另一个而不会有太大的功能差异。这篇文章:CountDownLatch vs. Semaphore可能会帮助您解决疑惑。CyclicBarrier
,它将永远不会重置自己,因此您最好使用CountDownLatch
,这样可以使代码更易于理解。Semaphore
的构造函数为例:JDK提供了两个构造函数。1 public Semaphore(int permits) {
2 sync = new NonfairSync(permits);
3 }
1 public Semaphore(int permits, boolean fair) {
2 sync = fair ? new FairSync(permits) : new NonfairSync(permits);
3 }
我们可以使用Semaphore(3,false)
代替Semaphore(3)
,两者都是创建非公平版本的信号量。但为什么JDK仍然提供了两个构造函数版本呢?因为从中选择合适的一个可以使代码更易于阅读和理解。
以下是我的意见:
CountDownLatch
允许线程 A 等待线程 B,但不要求线程 B 等待线程 A。这可以用于一些场景,其中一个线程需要不被打断地工作,而另一个线程必须在该线程的某些点上进行同步。
另一方面,CyclicBarrier
要求两个线程相互同步,这是两者之间的核心区别。