Java multi-thread series -- Principle and example of CountDownLatch in "JUC lock" 09

Source: Internet
Author: User

I have a general understanding of "exclusive lock" and "shared lock". In this chapter, we will learn about CountDownLatch. Like ReadWriteLock. ReadLock, CountDownLatch is also a "shared lock ". This chapter includes the following content: CountDownLatch introduction CountDownLatch source code analysis (based on JDK1.7.0 _ 40) CountDownLatch example CountDownLatch introduction CountDownLatch is a synchronization auxiliary class, before completing a group of operations being executed in other threads, it allows one or more threads to wait. Difference between CountDownLatch and CyclicBarrier (01) CountDownLatch is used to allow 1 or N threads to wait for other threads to complete execution, while CyclicBarrier allows N threads to wait for each other. (02) The counter of CountDownLatch cannot be reset; the counter of CyclicBarrier can be reset and used. Therefore, it is called a circular barrier. Next, let's take a look at the principle of javasicbarrier. CountDownLatch function list copy code CountDownLatch (int count) to construct a CountDownLatch initialized with the given count. // Keep the current thread waiting until the latch count reaches zero unless the thread is interrupted. Void await () // keep the current thread waiting until the latch is counted to zero unless the thread is interrupted or exceeds the specified waiting time. Boolean await (long timeout, TimeUnit unit) // decrease the number of latches. If the number reaches zero, all waiting threads are released. Void countDown () // returns the current count. Long getCount () // returns the string that identifies the lock and its status. String toString () copy the code CountDownLatch source code analysis (based on JDK1.7.0 _ 40) CountDownLatch complete source code (based on JDK1.7.0 _ 40) View CodeCountDownLatch is implemented through the "shared lock. Next, we will analyze three core functions in CountDownLatch: CountDownLatch (int count), await (), countDown (). 1. countDownLatch (int count) public CountDownLatch (int count) {if (count <0) throw new IllegalArgumentException ("count <0"); this. sync = new Sync (count) ;}note: This function creates a Sync object, and Sync inherits from the AQS class. The Sync constructor is as follows: Sync (int count) {setState (count);} setState () is implemented in AQS. The source code is as follows: protected final void setState (long newState) {state = newState;}: In AQS, state is a private volatile long object. For CountDownLatch, state indicates the "Lock counter". GetCount () in CountDownLatch is the final call to getState () in AQS, and the returned state object is the "Lock counter". 2. await () public void await () throws InterruptedException {sync. acquireSharedInterruptibly (1);} note: this function is actually called by the queue of AQS (1); the source code of acquireSharedInterruptibly () in AQS is as follows: copy the public final void Digest (long arg) throws InterruptedException {if (Thread. interrupted () throw new InterruptedException (); if (tryAcquireShared (arg) <0) doAcquireSharedInterruptibly (arg );} Copy Code Description: acquireSharedInterruptibly () is used to obtain the shared lock. If the current thread is interrupted, an exception InterruptedException is thrown. Otherwise, call tryAcquireShared (arg) to obtain the shared lock. If the attempt is successful, return. Otherwise, call doAcquireSharedInterruptibly (). DoAcquireSharedInterruptibly () will keep the current thread waiting until the current thread obtains the shared lock (or is interrupted. TryAcquireShared () is rewritten in CountDownLatch. java. Its source code is as follows: protected int tryAcquireShared (int acquires) {return (getState () = 0 )? 1:-1;} Note: tryAcquireShared () is used to try to obtain the shared lock. If "lock counter = 0", that is, if the lock is available, 1 is returned; otherwise, if the lock is not available,-1 is returned. Copy the code private void doAcquireSharedInterruptibly (long arg) throws InterruptedException {// create a Node with the "current thread", and the lock recorded in the Node is of the "shared lock" type; add the node to the end of the CLH queue. Final Node node = addWaiter (Node. SHARED); boolean failed = true; try {for (;) {// obtain the previous Node. // If the last node is the header of the CLH queue, "try to obtain the shared lock ". Final Node p = node. predecessor (); if (p = head) {long r = tryAcquireShared (arg); if (r> = 0) {setHeadAndPropagate (node, r); p. next = null; // help GC failed = false; return ;}/// (the header of the last node is not the header of the CLH Queue) The current thread waits until the shared lock is obtained. // If the thread has been interrupted while waiting, it will be interrupted again (restoring the previous interruption status ). If (shouldParkAfterFailedAcquire (p, node) & parkAndCheckInterrupt () throw new InterruptedException () ;}} finally {if (failed) cancelAcquire (node );}} copy Code Description: (01) addWaiter (Node. SHARED) is used to create a "current thread" Node, and the type of the lock recorded in the Node is "SHARED lock" (Node. and add the node to the end of the CLH queue. Node and CLH have already been described in detail in "Java multi-thread series --" JUC lock "03 fair lock (1)" and will not be repeated here. (02) node. predecessor () is used to obtain the previous node. If the previous node is the header of the CLH queue, "try to obtain the shared lock". (03) shouldParkAfterFailedAcquire () is the same as its name. If the thread waits after the attempt to obtain the lock fails, true is returned; otherwise, false is returned. (04) When shouldParkAfterFailedAcquire () returns true, parkAndCheckInterrupt () is called. The current thread enters the waiting state and continues running until the shared lock is obtained. ShouldParkAfterFailedAcquire () and parkAndCheckInterrupt functions in doAcquireSharedInterruptibly () are described in "Java multi-threaded series --" JUC lock "03 fair lock (1. 3. countDown () public void countDown () {sync. releaseShared (1);} Note: This function actually calls releaseShared (1) to release the shared lock. ReleaseShared () is implemented in AQS. The source code is as follows: copy the public final boolean releaseShared (int arg) {if (tryReleaseShared (arg) {doReleaseShared (); return true ;} return false;} copy the Code Description: The purpose of releaseShared () is to release the shared lock held by the current thread. It first tries to release the shared lock through tryReleaseShared. If the attempt is successful, return directly. If the attempt fails, use doReleaseShared () to release the shared lock. TryReleaseShared () in CountDownLatch. java is rewritten. The source code is as follows: copy the Code protected boolean tryReleaseShared (int releases) {// Decrement count; signal when transition to zero (;;) {// obtain the status int c = getState (); if (c = 0) return false; // "lock counter"-1 int nextc = C-1; // assign values using the CAS function. If (compareAndSetState (c, nextc) return nextc = 0 ;}} copy the Code Description: tryReleaseShared () is used to release the shared lock and set the value of "lock counter" to-1. Conclusion: CountDownLatch is implemented through the "shared lock. When CountDownLatch is created, a count parameter of the int type is passed. This parameter is the initial state of the "Lock counter", indicating that the "shared lock" can be obtained by the thread at the same time by count. When a thread calls the await () method of the CountDownLatch object, the thread will wait for the "shared lock" to be available before obtaining the "shared lock" to continue running. The condition that "shared lock" is available is that the value of "lock counter" is 0! The initial value of "lock counter" is count. When a thread calls the countDown () method of the CountDownLatch object, the "Lock counter"-1 is passed, after count threads call countDown (), the "Lock counter" is 0, and the previously mentioned waiting thread can continue to run! The above is the implementation principle of CountDownLatch. The CountDownLatch usage example is implemented through CountDownLatch: "The main thread" waits for "Five subthreads" to complete "specified job (sleep for 1000 ms)" and then continues to run. Copy code 1 import java. util. concurrent. countDownLatch; 2 import java. util. concurrent. cyclicBarrier; 3 4 public class CountDownLatchTest1 {5 6 private static int LATCH_SIZE = 5; 7 private static CountDownLatch doneSignal; 8 public static void main (String [] args) {9 10 try {11 doneSignal = new CountDownLatch (LATCH_SIZE); 12 13 // create 5 new tasks 14 for (int I = 0; I <LATCH_SIZE; I ++) 15 new InnerThread (). start (); 16 1 7 System. out. println ("main await begin. "); 18 //" main thread "waits for the completion of five tasks in the Thread Pool 19 doneSignal. await (); 20 21 System. out. println ("main await finished. "); 22} catch (InterruptedException e) {23 e. printStackTrace (); 24} 25} 26 27 static class InnerThread extends Thread {28 public void run () {29 try {30 Thread. sleep (1000); 31 System. out. println (Thread. currentThread (). getName () + "sleep 1000 ms. "); 32 // set CountDownLatch's The value is reduced by 133 doneSignal. countDown (); 34} catch (InterruptedException e) {35 e. printStackTrace (); 36} 37} 38} 39} copy the code running result: copy the code main await begin. thread-0 sleep 1000ms. thread-2 sleep 1000ms. thread-1 sleep 1000ms. thread-4 sleep 1000ms. thread-3 sleep 1000ms. main await finished. description of the Code copying result: the main thread uses doneSignal. await () waits for other threads to decrease doneSignal to 0. The other five InnerThread threads use doneSignal. countDown () to reduce the value of doneSignal by 1. When doneSignal is 0, the main thread is awakened and continues to be executed.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.