The JDK concurrency package provides several very useful tool classes. These tool classes provide us with a means of concurrent process control in the development. This article will introduce how to use CountDownLatch
and the internal implementation mechanism based on actual application scenarios.
What is CountDownLatch
CountDownLatch
, was introduced in JDK 1.5, allowing one or more threads to wait for other threads to complete operations before executing.
CountDownLatch
internally maintains a counter
whose initial value is the number of threads. The main thread executes the await method. If the counter
is greater than 0, it blocks and waits. When a thread finishes its task, the counter
value is decremented. When the counter
is 0, it means that all threads have completed their tasks, and the waiting main thread is awakened to continue execution.
Example
The main thread of the application wants to execute after all other threads are completed.
The main class that uses a thread pool to perform tasks for each worker. Responsible for initializing the CountDownLatch
, and then wait until all workers complete.
1 | public class CountDownLatchApplication { |
Worker class. Using TimeUnit.SECONDS.sleep
to simulate long running task.
1 | public class Worker implements Runnable { |
Output:
1 | worker2started! |
Principle of the implementation
CountDownLatch
implementation is mainly based on the java synchronizer AQS
.
It maintains an AQS
subclass internally and overrides related methods.
1 | private static final class Sync extends AbstractQueuedSynchronizer { |
Implementation of await
The main thread executes the await
method. If the state is not equal to 0 in the tryAcquireShared
method and returns -1, it is added to the waiting queue, and the main thread is suspended through LockSupport.park(this)
.
1 | private void doAcquireSharedInterruptibly(int arg) |
Implementation of countDown
The countDown
method delegates sync
to reduce the state
by one, which is to set the state
value through the unsafe.compareAndSwapInt
method.
1 | public void countDown() { |
If state
is 0, then wake up the main thread suspended in the await
method through LockSupport.unpark
.
1 | private void doReleaseShared() { |
Difference from CyclicBarrier
CyclicBarrier
allows a series of threads to wait for each other to reach a point. As the barrier indicates, this point is like a fence. The first arriving thread is blocked in front of the fence. It must wait until all threads have reached before it can pass the fence.CyclicBarrier
has a variableparties
, which indicates the number of threads that need to be reached. The thread that arrives first calls thebarrier.await
method to wait. Once the number of threads reaches the number specified by theparties
variable, the fence is opened and all threads can pass;CyclicBarrier
constructor accepts anotherRunnable
parameterbarrierAction
, which indicates the action to be taken when the barrier is opened.Null
indicates that no action is taken. Note that the action will be executed after the barrier is opened and before all other threads are run.CyclicBarrier
is reusable. When the last thread arrives, the fence is opened. After all threads pass, the fence is closed again to enter the next generation;CyclicBarrier.reset
method can reset the fence manually, and the waiting thread will receive aBrokenBarrierException
abnormal.
Conclusion
Through the introduction of this article, I hope everyone can understand the application scenario and working mechanism of CountDownLatch
.