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
CyclicBarrierallows 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.CyclicBarrierhas a variableparties, which indicates the number of threads that need to be reached. The thread that arrives first calls thebarrier.awaitmethod to wait. Once the number of threads reaches the number specified by thepartiesvariable, the fence is opened and all threads can pass;CyclicBarrierconstructor accepts anotherRunnableparameterbarrierAction, which indicates the action to be taken when the barrier is opened.Nullindicates that no action is taken. Note that the action will be executed after the barrier is opened and before all other threads are run.CyclicBarrieris 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.resetmethod 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.