CountDownLatch is a very practical tool class in the Java concurrency package, which can help us achieve synchronization and collaboration between threads. The core idea of CountDownLatch is to control the execution order of threads through a counter. When the counter value drops to 0, all waiting threads will be awakened and then begin to perform the next operation.
In Java, the implementation of CountDownLatch is based on the AbstractQueuedSynchronizer class. AbstractQueuedSynchronizer is a very important synchronizer. Many concurrency classes in Java are implemented based on it, such as Semaphore, ReentrantLock, ReadWriteLock, etc.
The core implementation class of CountDownLatch is Sync, which is an internal class inherited from AbstractQueuedSynchronizer. The following is the source code of the Sync class:
private static final class Sync extends AbstractQueuedSynchronizer { Sync(int count) { setState(count); } int getCount() { return getState(); } protected int tryAcquireShared(int acquires) { return (getState() == 0) ? 1 : -1; } protected boolean tryReleaseShared(int releases) { for (;;) { int c = getState(); if (c == 0) return false; int nextc = c-1; if (compareAndSetState(c, nextc)) return nextc == 0; } } }
There are three important methods in the Sync class:
tryAcquireShared(int acquires): Try to acquire the lock, if the value of the counter is equal to 0, indicating that all threads have completed execution, returns 1, otherwise -1 is returned, indicating failure to acquire the lock.
tryReleaseShared(int releases): Release the lock, decrement the counter value by 1, and return the counter value after decrementing 1. If the value of the counter decreases to 0, it means that all threads have completed execution and returns true, otherwise it returns false.
getCount(): Returns the current counter value.
The tryAcquireShared() method is the key to CountDownLatch, it will try to acquire the lock. If the value of the counter is equal to 0, it means that all threads have completed execution, and 1 can be returned, indicating that the lock acquisition was successful; otherwise -1 is returned, indicating that the lock acquisition failed. The basic method of the AbstractQueuedSynchronizer class is used here, namely the getState() method, which is used to obtain the status of the synchronizer.
The tryReleaseShared() method is used to release the lock, decrement the counter value by 1, and return the counter value after decrementing 1. If the value of the counter decreases to 0, it means that all threads have completed execution and returns true, otherwise it returns false. The basic method of the AtomicInteger class is used here, namely the compareAndSetState() method, which is used to compare and set the status of the synchronizer.
The working principle of CountDownLatch is very simple. It controls the execution order of threads through a counter. When the counter value drops to 0, all waiting threads will be awakened and then begin to perform the next operation.
CountDownLatch is a multi-thread collaboration tool class that allows one or more threads to wait for other threads to complete an operation before continuing. CountDownLatch has a counter. When the counter value becomes 0, the waiting thread will be awakened. The use of CountDownLatch is very simple, mainly including two methods: await() and countDown().
await() method: This method blocks the current thread until the counter value becomes 0.
countDown() method: This method will decrement the counter value by 1.
The following is a simple sample code:
public class CountDownLatchDemo { public static void main(String[] args) throws InterruptedException { final int count = 3; final CountDownLatch latch = new CountDownLatch(count); for (int i = 0; i < count; i++) { new Thread(() -> { // 线程执行任务 System.out.println(Thread.currentThread().getName() + " 执行任务..."); // 任务执行完毕,计数器减1 latch.countDown(); }).start(); } // 等待所有任务执行完毕 latch.await(); System.out.println("所有任务执行完毕..."); } }
In this sample code, we create a CountDownLatch object and initialize the counter to 3. Then 3 threads are created, each thread performs a task. After the task is completed, the counter is decremented by 1. Finally, call the latch.await() method in the main thread to wait for all tasks to be completed.
The implementation principle of CountDownLatch is based on the AbstractQueuedSynchronizer class. When we call the await() method, the thread will try to acquire the lock. If the counter value is not 0, the lock acquisition fails and the thread will be added to the synchronization queue and blocked. When we call the countDown() method, the counter value will be reduced by 1. If the counter value is reduced to 0, it means that all threads have completed execution. At this time, the threads in the synchronization queue will be awakened and continue to perform the next operation.
Specifically, in the Sync class, the tryAcquireShared(int acquires) method will try to acquire the lock. If the value of the counter is equal to 0, it means that all threads have completed execution and returns 1. Otherwise, it returns -1, which means Failed to acquire lock. The tryReleaseShared(int releases) method is used to release the lock, decrement the counter value by 1, and return the counter value after decrementing 1. If the value of the counter decreases to 0, it means that all threads have completed execution and returns true, otherwise it returns false.
CountDownLatch is a very practical tool class that can help us achieve synchronization and collaboration between threads. The following introduces some common application scenarios of CountDownLatch:
Waiting for multiple threads to complete: If there are multiple threads that need to be executed, but you must wait for all threads to complete before proceeding to the next step. This can be achieved using CountDownLatch. We can create a CountDownLatch object and initialize the counter value to the number of threads. After each thread completes execution, call the countDown() method to decrement the counter by 1. Finally, call the await() method in the main thread to wait for all threads to complete execution.
Control the execution order of threads: If there are multiple threads that need to be executed in a specific order, you can use CountDownLatch to achieve this. We can create multiple CountDownLatch objects, and the counter value of each object is 1, indicating that only one thread can execute. After the thread completes execution, call the countDown() method of the next CountDownLatch object to wake up the next thread.
Waiting for the occurrence of external events: If we need to wait for the occurrence of an external event, such as the establishment of a network connection or the completion of reading a file, we can use CountDownLatch to achieve this. We can create a CountDownLatch object in the main thread, initialize the counter value to 1, and then wait for the external event to occur in another thread. When an external event occurs, call the countDown() method of the CountDownLatch object to wake up the main thread to continue execution.
Control the number of concurrent threads: If we need to control the number of concurrent threads, we can use CountDownLatch to achieve it. We can create a CountDownLatch object and initialize the counter value to the number of threads. After each thread completes execution, call the countDown() method to decrement the counter by 1. If a thread needs to wait for other threads to complete execution, it can call the await() method to wait for the counter value to become 0.
The above is the detailed content of How to use CountDownLatch class from Java Concurrency Toolkit?. For more information, please follow other related articles on the PHP Chinese website!