Understanding and Using CountDownLatch in Java for Thread Coordination
This article explains the concept of Java's CountDownLatch, compares it with join(), demonstrates how to coordinate thread‑pool tasks using the latch, provides complete example code, and details its internal mechanism and common methods for synchronizing concurrent operations.
Wait for Threads with CountDownLatch
The article introduces the problem of needing to wait for multiple threads or thread‑pool tasks to finish before proceeding with the main thread, and relates this to the gaming concept of waiting for all teammates before starting a team fight.
Creating Threads with join()
// 创建线程1
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
// do something
}
});
t1.start();
// 创建线程2
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
// do something
}
});
t2.start();
// 等待线程 1和线程 2 执行完
t1.join();
t2.join();Using join() works when threads are created directly, but in real applications tasks are usually submitted to a thread pool, which does not provide a join() method.
ThreadPool and the Need for CountDownLatch
// 创建固定线程数的线程池
ExecutorService executorService = Executors.newFixedThreadPool(2);
// 任务一
executorService.submit(new Runnable() {
@Override
public void run() {
// do something
}
});
// 任务二
executorService.submit(new Runnable() {
@Override
public void run() {
// do something
}
});Because the thread pool lacks join() , we need a coordination mechanism; this is where CountDownLatch comes into play.
CountDownLatch Usage
public static void main(String[] args) throws InterruptedException {
// 创建 CountDownLatch
CountDownLatch countDownLatch = new CountDownLatch(2);
// 创建固定线程数的线程池
ExecutorService executorService = Executors.newFixedThreadPool(2);
// 任务一
executorService.submit(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1200); // 让此任务执行 1.2s
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我是任务一");
countDownLatch.countDown();
}
});
// 任务二
executorService.submit(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000); // 让此任务执行 1.0s
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我是任务二");
countDownLatch.countDown();
}
});
// 等待任务执行完成
countDownLatch.await();
System.out.println("程序执行完成~");
}The program prints the two task messages after their respective sleeps and finally prints "程序执行完成~" only after both tasks have called countDown() , demonstrating that the main thread waited for all workers.
CountDownLatch Working Principle
CountDownLatch holds an internal volatile counter initialized with the value passed to its constructor. Each call to countDown() decrements the counter. Calls to await() block the current thread until the counter reaches zero, at which point waiting threads are released.
Execution Flow
The latch’s await() method checks the counter; if it is not zero, the thread enters a waiting state. When other threads invoke countDown() and the counter becomes zero, all waiting threads are awakened and continue execution.
Common Methods
// Blocks until count reaches 0
public void await() throws InterruptedException { }
// Blocks until count reaches 0 or timeout expires
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { }
// Decrements the count by one
public void countDown() { }Conclusion
CountDownLatch provides a simple way to make a thread wait until a set of other threads have completed their work, similar to waiting for all players to gather before starting a team fight in a game. By initializing the latch with a positive count and calling countDown() after each task, the main thread can reliably synchronize concurrent operations.
Reference & Acknowledgements
Source: www.jianshu.com/p/128476015902
Full-Stack Internet Architecture
Introducing full-stack Internet architecture technologies centered on Java
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.