This class enables a java thread to
wait until other set of threads completes their tasks.
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.
A CountDownLatch is initialized with a given count and await() methods block until
the current count reaches zero due to invocations of the countDown()
method, after which all waiting threads are released and any subsequent
invocations of await return immediately.
This is a one-shot phenomenon i.e
the count cannot be reset. If you need a version that
resets the count, consider using a CyclicBarrier.
Sample usage:
Here is a pair of classes in which a
group of worker threads use two countdown latches:
The first is a start signal that
prevents any worker from proceeding until the driver is ready for them to
proceed.
The second is a completion signal
that allows the driver to wait until all workers have completed.
class Driver { // ...
void main() throws InterruptedException
{
CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(N);
for (int i
= 0; i < N; ++i) // create and start
threads
new Thread(new Worker(startSignal, doneSignal)).start();
doSomethingElse(); // don't let run yet
startSignal.countDown(); // let all threads proceed
doSomethingElse();
doneSignal.await(); // wait for all to finish
}
}
class Worker implements Runnable {
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;
Worker(CountDownLatch startSignal,
CountDownLatch doneSignal) {
this.startSignal = startSignal;
this.doneSignal = doneSignal;
}
public void run()
{
try {
startSignal.await();
doWork();
doneSignal.countDown();
} catch (InterruptedException ex) {} // return;
}
void doWork()
{ ... }
}
Another typical usage would be to
divide a problem into N parts, describe each part with a Runnable that executes
that portion and counts down on the latch, and queue all the Runnables to an
Executor.
When all sub-parts are complete, the
coordinating thread will be able to pass through await. (When threads must repeatedly count
down in this way, instead use a CyclicBarrier).
class Driver2 { // ...
void main() throws InterruptedException
{
CountDownLatch doneSignal = new CountDownLatch(N);
Executor e = ...
for (int i
= 0; i < N; ++i) // create and start
threads
e.execute(new WorkerRunnable(doneSignal, i));
doneSignal.await(); // wait for all to finish
}
}
class WorkerRunnable implements Runnable {
private final CountDownLatch doneSignal;
private final int i;
WorkerRunnable(CountDownLatch doneSignal, int i) {
this.doneSignal = doneSignal;
this.i = i;
}
public void run()
{
try {
doWork(i);
doneSignal.countDown();
} catch (InterruptedException ex) {} // return;
}
void doWork()
{ ... }
}
Memory consistency effects: Until the
count reaches zero, actions in a thread prior to calling countDown()
happen-before actions following a successful return from a corresponding
await() in another thread.
Working of
CountDownLatch
|
CountDownLatch.await()
Any thread, usually main
thread of application, which calls CountDownLatch.await() will wait until count reaches zero or its interrupted by another Thread.
CountDownLatch.countDown()
Each invocation of method decreases the initial count set in constructor, by 1. So, when all N threads have call this method, count reaches to zero, and main thread is allowed to resume its execution past await() method.
Each invocation of method decreases the initial count set in constructor, by 1. So, when all N threads have call this method, count reaches to zero, and main thread is allowed to resume its execution past await() method.
Usages of CountDownLatch in java
1. Achieving Maximum Parallelism: Sometimes we want to
start a number of threads at the same time to achieve maximum parallelism.
For example, we want to test a
class for being singleton. This can be done easily if we create a
CountDownLatch with initial count 1, and make wait all threads to wait of
latch. A single call to countDown() method will resume execution for all
waiting threads in same time.
2. Wait N threads to complete
before start execution: For example an application start-up class wants to
ensure that all N external systems are UP and running before handling the user
requests.
3. Deadlock detection: A very handy use
case in which you can use N threads to access a shared resource with different
number of threads in each test phase, and try to create a deadlock.
No comments:
Post a Comment