In-depth understanding of CountDownLatch counter
Other knowledge points
In-depth understanding of Java multi-threading basics In-depth understanding of aqs
ReentrantLock usage In
-depth understanding of semaphore Semaphore
In-depth understanding of the three major features
of concurrency In-depth understanding of concurrent programming In-depth understanding of CAS
In-depth understanding of CountDownLatch
Java thread pool
Usage
Detailed usage of CountDownLatch
CountDownLatch implementation principle
The following example to debug to walk smoothly
CountDownLatch countDown = new CountDownLatch(5);
System.out.println(" 准备多线程处理任务 ");
IntStream.rangeClosed(1, 6).forEach(x -> {
new Thread(() -> {
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(" 线程开始 ----- " + Thread.currentThread().getName());
countDown.countDown();
}, x + "").start();
});
try {
countDown.await();
// 可以设置等待时间
// countDown.await(6, TimeUnit.MINUTES);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(" 准备多线程处理任务 结束 ");
System.out.println(" ---------------------- ");
System.out.println(" 结束 mian ---------- ");
复制代码
When used, it will be blocked at countDown.await(); and countDown.countDown(); will count.
What is the internal principle? Let's debug
t0 thread
The default is count minus 1
tryReleaseShared method
You can see that the initialization state is 5, where each thread is -1 and then cas sets the value
This is true for the remaining t2 t3 t4 t5 threads
Finally, let's look at the await method
First of all, since we are await in the main thread and other threads are asynchronous, they will definitely block here, and will enter here to judge whether the state variable is 0
You can see that if the state is 0, it returns 1, otherwise it returns -1
Then build the main thread node and try to get the state variable again
Here the shouldParkAfterFailedAcquire method sets the node head node variable to -1
and returns true again, and finally enters the parkAndCheckInterrupt() method to park the main thread
Knowing that all threads are executed, enter the doReleaseShared() method to wake up the main thread
You can see that the next node node thread of the head node is the main thread
Then use the following unpark to wake up the main thread
at last
The bottom layer of CountDownLatch implementation principle is based on AbstractQueuedSynchronizer, and the count specified in the CountDownLatch constructor is directly assigned to the state of AQS;
Every countDown() is release(1) minus 1, and unpark blocks the thread when it is finally reduced to 0;
This step is performed by the last thread that executes the countdown method.
When the await() method is called, the current thread will judge whether the state attribute is 0. If it is 0, it will continue to execute. If it is not 0, the current thread will enter the waiting state until a thread sets the state attribute to 0. If it is 0, it will wake up the thread waiting in the await() method.
The difference between CountDownLatch and Thread.join
Before that, we can use join to block and wait for other threads to complete operations.
The difference between CountDownLatch and Thread.join
- The function of CountDownLatch is to allow one or more threads to wait for other threads to complete operations. It looks a bit similar to the join() method, but it provides a more flexible API than join().
- CountDownLatch can manually control to call the countDown() method n times in n threads to decrement the counter by one, or it can call n times in one thread to perform the decrement operation. The implementation principle of join() is to keep checking whether the join thread is alive, and if the join thread is alive, let the current thread wait forever.
Relatively speaking, CountDownLatch is more flexible to use.
join method