In-depth understanding of CountDownLatch counter

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
insert image description here

tryReleaseShared method

insert image description here

You can see that the initialization state is 5, where each thread is -1 and then cas sets the value
insert image description here

This is true for the remaining t2 t3 t4 t5 threads

Finally, let's look at the await method

insert image description here

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

insert image description here

You can see that if the state is 0, it returns 1, otherwise it returns -1
insert image description here

Then build the main thread node and try to get the state variable again

insert image description here

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

insert image description here

You can see that the next node node thread of the head node is the main thread

insert image description here

Then use the following unpark to wake up the main thread

insert image description here

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;

insert image description here

Every countDown() is release(1) minus 1, and unpark blocks the thread when it is finally reduced to 0;

insert image description here

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.

Blocking in doAcquireSharedInterruptibly

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
insert image description here

Guess you like

Origin juejin.im/post/7231804086382034999