Understanding and Using CountDownLatch in Java Concurrency
This article explains the purpose, basic methods, best‑practice usage, and typical scenarios of Java's CountDownLatch utility, providing code examples and a comparison with Thread.sleep to help developers synchronize multiple threads effectively.
2.5 CountDownLatch
The previous two synchronization tools, synchronized and ReentrantLock , are like swords that solve thread‑safety problems; now we explore the functional classes in the java.util.concurrent package, focusing on CountDownLatch.
In performance testing with multiple threads, we often need to synchronize threads at a specific event or time point, such as a timed red‑packet grab or concurrent data initialization. All threads must reach a barrier before proceeding, a common requirement in flow‑type test scenarios.
CountDownLatch is a relatively simple synchronization tool that allows one or more threads to wait until a set of operations performed by other threads completes. It works like a collection point in JMeter: all threads gather, then continue independently.
The workflow of CountDownLatch is based on a thread‑safe counter:
(1) Create the latch and set the count. (2) Worker threads perform their tasks and decrement the counter. (3) The waiting thread (usually the main thread) blocks (optionally with a timeout) until the counter reaches zero, then continues.
2.5.1 Basic Methods
The constructor of CountDownLatch is:
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}The single int count parameter specifies how many threads must reach the barrier; a negative value throws an exception.
To decrement the counter, use:
public void countDown() {
sync.releaseShared(1);
}Typically this call is placed inside a try‑catch‑finally block to guarantee execution.
To wait for the counter to reach zero, two overloads are available:
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}The first method waits indefinitely, while the second allows a timeout.
2.5.2 Best Practice Example
The following example demonstrates a typical CountDownLatch usage:
package org.funtester.performance.books.chapter02.section5;
import java.util.concurrent.CountDownLatch;
/**
* CountDownLatch demo
*/
public class CountDownLatchDemo {
public static void main(String[] args) {
CountDownLatch countDownLatch = new CountDownLatch(3); // create latch with count 3
for (int i = 0; i < 3; i++) {
new Thread(() -> {
try {
Thread.sleep(100); // simulate work
} catch (InterruptedException e) {
throw new RuntimeException(e);
} finally {
countDownLatch.countDown(); // decrement counter
}
System.out.println(System.currentTimeMillis() + " task completed " + Thread.currentThread().getName());
}).start();
}
System.out.println(System.currentTimeMillis() + " waiting for tasks " + Thread.currentThread().getName());
try {
countDownLatch.await(); // wait for counter to reach zero
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(System.currentTimeMillis() + " wait finished " + Thread.currentThread().getName());
}
}The program creates a latch with count 3, starts three threads that each sleep 100 ms, decrement the latch, and print a log. The main thread calls await() and blocks until all three threads finish, then prints a final message.
1698497720691 waiting for tasks main
1698497720791 task completed Thread-0
1698497720791 task completed Thread-2
1698497720791 task completed Thread-1
1698497720791 wait finished mainThis output shows the main thread waiting at await() until the three worker threads complete and the latch reaches zero.
2.5.3 Usage Scenarios
Common scenarios for CountDownLatch include:
Thread waiting: one or more threads wait until a group of other threads finish their tasks (e.g., concurrent data initialization).
Start/stop signaling: use the latch to signal a set of threads to start or finish (e.g., timed red‑packet grab).
Compared with Thread.sleep() , CountDownLatch offers more precise control, better performance (threads are blocked instead of consuming CPU), graceful timeout handling, simpler code, and clearer readability.
However, CountDownLatch has limitations: it cannot be reused after creation, and its count cannot be increased, making it unsuitable for complex coordination requiring dynamic adjustments.
In summary, CountDownLatch is ideal for simple, one‑time waiting scenarios, while more advanced synchronization tools are needed for complex multithreaded coordination.
Book title: Performance Testing from Java .
If you find this content helpful, consider supporting the author; a small donation grants early access to unpublished chapters and upcoming video tutorials.
FunTester
10k followers, 1k articles | completely useless
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.