Member-only story
Some Coding Challenges: Implementing a Countdown Latch.
The task is to implement a so called CountdownLatch in Java. It will be initialized with an integer count
and provides two methods void await()
and void countDown()
. Threads that call countDown
trigger the count
to decrease be 1
each time. Threads calling the await
are blocked until the count
has reached the value 0
.
A possible implementation could look like so:
class CountdownLatch {
private int count;
public CountdownLatch(int count) {
this.count = count;
}
public synchronized void await() {
while (this.count > 0) { // verify count to still be positive
try {
wait();
} catch (InterruptedException e) {
break;
}
}
}
public synchronized void countDown() {
count -= 1;
notifyAll(); // notify awaiters to check condition
}
}
This can be seen in action like so:
var cl = new CountdownLatch(5);
// schedule 5 threads that count-down the latch
IntStream.range(0, 5)
.mapToObj(i -> new Runnable() {
@Override
public void run() {
System.out.println("Task " + i + " is running.");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
cl.countDown();
}
})
.map(Thread::new)
.forEach(Thread::start);
// schedule the main thread to await
cl.await();
System.out.println("Awaited all the tasks to finish.");
Let mention one important aspect of the CountdownLatch
implementation — the notifyAll
. Here it is vital to use notifyAll
and not just notify
. The reason for this is that there could have been more than one thread calling the await
method. A simple notify
would only awake one of these and leave the others in a forever waiting state.
Even though this all looks like a very simple construct, let me note that this pattern has many applications and can help organizing your code very well when it comes to parallelization. Anyway, the above code deems as an exercise, a more modern approach of synchronizing such parallelizations is the use of CompletableFutures
.
Thank you for reading!