CountDownLatch vs. Semaphore
Is there any advantage of using
java.util.concurrent.CountdownLatch
instead of
java.util.concurrent.Semaphore?
As far as I can tell the following fragments are almost equivalent:
1. Semaphore
final Semaphore sem = new Semaphore(0);
for (int i = 0; i < num_threads; ++ i)
{
Thread t = new Thread() {
public void run()
{
try
{
doStuff();
}
finally
{
sem.release();
}
}
};
t.start();
}
sem.acquire(num_threads);
2: CountDownLatch
final CountDownLatch latch = new CountDownLatch(num_threads);
for (int i = 0; i < num_threads; ++ i)
{
Thread t = new Thread() {
public void run()
{
try
{
doStuff();
}
finally
{
latch.countDown();
}
}
};
t.start();
}
latch.await();
Except that in case #2 the latch cannot be reused and more importantly you need to know in advance how many threads will be created (or wait until they are all started before creating the latch.)
So in what situation might the latch be preferable?
CountDownLatch
is frequently used for the exact opposite of your example. Generally, you would have many threads blocking on await()
that would all start simultaneously when the countown reached zero.
final CountDownLatch countdown = new CountDownLatch(1);
for (int i = 0; i < 10; ++ i) {
Thread racecar = new Thread() {
public void run() {
countdown.await(); //all threads waiting
System.out.println("Vroom!");
}
};
racecar.start();
}
System.out.println("Go");
countdown.countDown(); //all threads start now!
You could also use this as an MPI-style "barrier" that causes all threads to wait for other threads to catch up to a certain point before proceeding.
final CountDownLatch countdown = new CountDownLatch(num_thread);
for (int i = 0; i < num_thread; ++ i) {
Thread t= new Thread() {
public void run() {
doSomething();
countdown.countDown();
System.out.printf("Waiting on %d other threads.",countdown.getCount());
countdown.await(); //waits until everyone reaches this point
finish();
}
};
t.start();
}
That all said, the CountDownLatch
can safely be used in the manner you've shown in your example.
CountDownLatch is used to start a series of threads and then wait until all of them are complete (or until they call countDown()
a given number of times.
Semaphore is used to control the number of concurrent threads that are using a resource. That resource can be something like a file, or could be the cpu by limiting the number of threads executing. The count on a Semaphore can go up and down as different threads call acquire()
and release()
.
In your example, you're essentially using Semaphore as a sort of CountUPLatch. Given that your intent is to wait on all threads finishing, using the CountdownLatch
makes your intention clearer.
Short summary:
-
Semaphore
andCountDownLatch
serves different purpose. -
Use
Semaphore
to control thread access to resource. -
Use
CountDownLatch
to wait for completion of all threads
Semaphore
definition from Javadocs:
A
Semaphore
maintains a set of permits. Eachacquire()
blocks if necessary until a permit is available, and then takes it. Eachrelease()
adds a permit, potentially releasing a blocking acquirer.
However, no actual permit objects are used; the Semaphore
just keeps a count of the number available and acts accordingly.
How does it work?
Semaphores are used to control the number of concurrent threads that are using a resource.That resource can be something like a shared data, or a block of code (critical section) or any file.
The count on a Semaphore
can go up and down as different threads call acquire()
and release()
. But at any point of time, you can't have more number of threads greater than Semaphore count.
Semaphore
Use cases:
- Limiting concurrent access to disk (as performance degrades due to competing disk seeks)
- Thread creation limiting
- JDBC connection pooling / limiting
- Network connection throttling
- Throttling CPU or memory intensive tasks
Have a look at this article for semaphore uses.
CountDownLatch
definition from Javadocs:
A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.
How does it work?
CountDownLatch
works by having a counter initialized with number of threads, which is decremented each time a thread complete its execution. When count reaches to zero, it means all threads have completed their execution, and thread waiting on latch resume the execution.
CountDownLatch
Use cases:
- Achieving Maximum Parallelism: Sometimes we want to start a number of threads at the same time to achieve maximum parallelism
- Wait N threads to completes before start execution
- Deadlock detection.
Have a look at this article to understand CountDownLatch
concepts clearly.
Have a look at Fork Join Pool at this article too. It has some similarities to CountDownLatch
.