preface

This article introduces the principle and application of countDownLatch, a high-powered test point for interviewCopy the code

CountDownLatch features

  • CountDownLatch has two main methods that block when one or more threads call the await method.

  • Another thread calling the countDown method will decrement the counter by one (the thread calling the countDown method will not block).

  • When the value of the counter becomes 0, the thread blocked by the await method is woken up and continues execution.

Application scenarios

Typical application scenarios

For example, in parallel computing, when a certain processing has a large amount of computation, the calculation task can be divided into multiple sub-tasks. After all the sub-tasks are completed, the parent task will get the calculation results of all the sub-tasks and summarize them.Copy the code

Introduction of the principle


Above explanation

  • The TA thread instantiates the CountDownLatch object with an initial count of 3
  • TA calls await so that the current thread waits for count to be zero similar to hitting pause while watching a video
  • Another T1 thread calls the countDown method of the CountDownLatch object to make the count 2
  • The T2 thread makes count 1
  • The T3 thread makes count 0
  • At this point, the TA thread in the “paused” state is awakened to continue executing

Further explanation

  • CountDownLatch is a counter latch that performs a function similar to blocking the current thread; that is, one or more threads wait until an operation performed by another thread completes.

  • CountDownLatch is initialized with a given counter whose operation is atomic, meaning that only one thread can operate on the counter at a time.

  • A thread calling the await method of this class will block until another thread calls the countDown method to zero the value of the current counter, decreasing the value of the countDown counter by one each time.

  • When the counter value drops to zero, all threads that are waiting because of calling the await() method continue to execute.

  • This happens only once, because counters cannot be reset, and if your business needs a version that resets count times, consider using CycliBarrier

DEMO code analysis

This example includes thread pools and CountDownLatch content, which is more in line with real-world usage scenariosCopy the code


Elaborate on the above example

An explanation for CountDownLatch
  • Initialize a CountDownLatch with the initial count=5

  • Call the countDownLatch method count+-1, that is, count=count-1. The count value decreases by one for each call

  • Calling the await method causes the thread initializing CountDownLatch to wait for the count value to be zero before continuing

A thread pool description of CountDownDatch
  • The main thread creates a CountDownLatch with count 5

  • The main thread creates a pool of five core threads

  • Five threads are submitted to the thread pool and the countDownLatch object is passed to the child thread

  • The countDown method is called when each child thread executes to subtract the count by one

  • The main thread calls await and waits for count to change to 0

  • If count becomes 0, the main thread continues execution

Source code analysis

java.util.concurrent.CountDownLatch 
Copy the code

In the process of analyzing the source code, we focus on the red circle on my screenshot and then we slowly read the source code bit by bit


Setting count to state calls the setState method of the AQS classCopy the code

The variable is volatile to ensure that the variable is 1, visible, 2, ordered to prevent instruction reordering, and 3, atomicityCopy the code

Here's a quick introduction to visibility


Above explanation

  • Each thread will have A local memory let’s say thread A has local memory A which holds A copy of the shared variables in main memory

  • Thread A makes changes to A copy of A shared variable in local memory and then synchronously flusher it to main memory immediately

  • It also causes the thread that forced the cache to clear data

  • The latest data must be re-read from main memory

Moving on to CountDownLatch source analysisCopy the code

The internal class Sync, which inherits AQS, is instantiated when CountDownLatch is initialized and count is passed to the state variable of AQSCopy the code

CountDownLatch await method calls the AQS acquireSharedInterruptibly method and introduced into the parameter 1 next analysis of the methodCopy the code

Try to obtain tryAcquireShared in shared mode. This method queries whether the object's state is allowed to be retrieved in shared mode, and if so, retrieves it. This method is always called when the thread executes to acquire the shared lock. If the method reports failure, the fetch method may queue the thread, if it (that is, the thread) has not been queued, until another thread signals release. Default implementation throws an UnsupportedOperationException "return: a) < 0: a negative return said failure; B) 0:0 indicates that the lock is successfully obtained in the shared mode, but subsequent shared locks will not be successfully obtained. C) > 0: if the value is greater than 0, the lock is successfully obtained in the shared mode, and subsequent shared locks may also be successfully obtained. In this case, the subsequent waiting threads must check whether the lock is valid.Copy the code

Take a look at the implementation of AQS subclass Sync's tryAcquireShared method




In this logical process, a large number of CAS are used for atomic modification. When the modification fails, for(;) is passed. To recycle, which means "doAcquireSharedInterruptibly" using a spin lock (spin + CAS) to ensure that in the case of multi-threaded concurrent, queue node status is correct and the correctness of the waiting queue, led to the current node or access a Shared lock is successful, or suspended waiting for wake upCopy the code



We need a notification signal, mainly because the current thread is about to be suspended (park). If waitStatus is' SIGNAL ', there is no need to modify it but should be suspended. If waitStatus is' CANCELLED ', the prev has been CANCELLED and is invalid, there is no need to modify the waitStatus of the invalid node. You need to find a preV that works first. Therefore, all that remains is if waitStatus is' 0 'and' CONDITION '(note that waitStatus' CONDITION' is not in the wait queue, so waitStatus cannot be 'CONDITION'), We need to change the waitStatus of the prev to 'SIGNAL' using CAS, and only if the change succeeds can the current thread safely be suspended. It is also important to note that the CAS operation of this method has no spin, so it always returns false after the CAS operation. The outer method uses spin, and when it returns false, this method is called again to check that the current node has a valid prev. And its waitStatus is' SIGNAL 'in which case the current thread is suspended (park).Copy the code


Bidirectional linked list data structures
The source code analysis is not finished and will continue to be analyzed in the next articleCopy the code

DEMO code link

https://gitee.com/pingfanrenbiji/myconcurrent/tree/master/src/main/java/pers/hanchao/concurrent/eg14
Copy the code

Refer to the article

https://www.jianshu.com/p/9ee0194d598c
Copy the code