CountDownLatch
in java is a high-level synchronization utility which is used to prevent a particular thread to start processing until all threads are ready.
But, Semaphore
can totally do the same thing. So, what's the merit of CountDownLatch
?
One more question: If CountDownLatch
do have some merits, Why It was designed to used only once? I think it's easy to add a set method to reset the count.
Semantically, they're different; and that matters, because it makes your code easier to read. When I see a Semaphore, I immediately start thinking "a limited amount of a shared resource." When I see a CountDownLatch, I immediately start thinking "a bunch of threads waiting for the 'go!' signal." If you give me the former in code that actually needs the latter, it's confusing.
In this sense, a Semaphore being used as a CountDownLatch is a bit like a garden-path sentence; while technically correct, it leads people astray and confuses them.
In terms of more pragmatic uses, a CountDownLatch is just simpler if that's all you need. Simpler is better!
As for reusing a CountDownLatch, that would complicate its usage. For instance, let's say you're trying to queue up threads A, B, and C for some work. You have them await on the latch, and then you release it. Then you reset it, presumably to queue up threads D, E and F for some other work. But what happens if (due to a race condition), thread B hasn't actually been released from the first latch yet? What if it hadn't even gotten to the await()
call yet? Do you close the gate on it, and tell it to wait with D, E and F for the second opening? That might even cause a deadlock, if the second opening depends on work that B is supposed to be doing!
I had the same questions you did about resetting when I first read about CountDownLatch. But in practice, I've rarely even wanted to reset one; each unit of "wait then go" (A-B-C, then D-E-F) naturally lends itself to creating its own CountDownLatch to go along with it, and things stay nice and simple.