HuntExams Academy logo
JavaAdvanced#concurrency

What is a CountDownLatch?

Answer

A synchronization aid that lets one or more threads wait until a set of operations in other threads completes, implemented by counting down from an initial value; once it hits zero, waiting threads proceed.

Example

CountDownLatch latch = new CountDownLatch(3);
// each worker thread calls latch.countDown() when done
latch.await(); // main thread blocks until count reaches 0

Detailed explanation

CountDownLatch is a synchronization aid in java.util.concurrent that allows one or more threads to wait until a specified number of events has occurred. You construct it with a non-negative count, such as new CountDownLatch(3). Each call to countDown() reduces the count by one, and await() blocks the calling thread until the count reaches zero. It is useful when a coordinating thread must wait for several independent tasks, such as loading configuration, warming a cache, and preparing application resources.

The count represents completion signals, not registered threads. Three workers may each signal once, or one worker may signal three times; the latch does not track which thread calls countDown(). Calling countDown() does not wait for other workers. When the count reaches zero, all threads waiting on await() become eligible to run, and subsequent await() calls return immediately. Further countDown() calls have no effect. A latch is one-shot: its count cannot be reset, so repeated coordination requires new instances or another synchronizer, such as CyclicBarrier or Phaser.

In standard JDK implementations, CountDownLatch uses AbstractQueuedSynchronizer, with the remaining count stored as synchronization state. Countdown operations update that state atomically, while waiting threads use the synchronizer's shared waiting mechanism rather than continuously polling. The transition to zero releases shared waiters. Its memory-consistency guarantee is also important: actions in a thread before countDown() happen-before actions following a successful return from a corresponding await() in another thread. This makes preceding writes visible to the waiting thread, but does not by itself make concurrent worker updates to shared mutable data safe.

For the example, the main thread waits until three countdown calls occur. Workers commonly call countDown() in a finally block so that exceptions do not leave the coordinator waiting indefinitely. However, reaching zero then means workers finished their attempts, not necessarily that they succeeded; failures need separate reporting. await() is interruptible and throws InterruptedException, while await(timeout, unit) returns false if the timeout expires. Interviewers usually expect these lifecycle, visibility, and failure-handling details, not just the basic counting behaviour.

Key points to remember

  • The initial count measures required signals, not the number of participating threads.
  • await() blocks until zero; countDown() decrements without waiting for other tasks.
  • Reaching zero releases all waiters, and the latch cannot be reset.
  • The happens-before guarantee makes writes preceding countdown visible after a successful await.
  • Use interruption handling, timeouts, and separate failure reporting for robust coordination.

Common mistakes candidates make

  • Assuming each worker can decrement the latch only once or that countDown() blocks.
  • Skipping countDown() on exception paths, potentially leaving await() blocked forever.
  • Treating a zero count as proof of successful execution or expecting the latch to be reusable.

Likely follow-up questions

How does CountDownLatch differ from CyclicBarrier?

CountDownLatch lets threads wait for signals from other threads, and signalling threads do not have to wait themselves. CyclicBarrier makes a fixed number of participants wait for one another at a rendezvous point and can be reused across rounds.

What happens if a worker fails before calling countDown()?

The count may never reach zero, so an untimed await() can wait indefinitely unless interrupted. Put the completion signal in finally when appropriate, capture failures separately, and consider a timed await().

Can CountDownLatch cause problems with a fixed-size thread pool?

Yes: if all pool threads are occupied by tasks waiting on a latch, queued tasks responsible for decrementing it cannot run. Avoid scheduling blocking coordinators and their dependent workers in a way that exhausts the same pool.

Interview tip: Explain the count-to-zero flow using the three-worker example, then mention one-shot behaviour, memory visibility, and countdown in finally.

Related Interview Questions

1
JavaAdvanced#concurrency

What is a ThreadLocal and when would you use it?

Open
2
JavaIntermediate#concurrency

What is the difference between Thread.sleep() and Object.wait()?

Open
3
JavaAdvanced#concurrency

What is the difference between ReentrantLock and synchronized?

Open