CountDownLatch usage and principle

Main methods :

Constructor CountDownLatch (int n)
blocking method latch.await () blocks the current thread until the latch status is completed
count by one latch.countDown () is decremented by 1 until the state change 0

 

For example scenario :

1. The long-distance race, running a total of two people together, everyone's ready to wait in place, the Starter ready to see every record once, not ready to reduce the number 1, until the number is ready to issuing the order starting from 0

public static void main(String[] args) throws InterruptedException {
    final CountDownLatch latch = new CountDownLatch(2);

    new Thread(()->{
        try {
            System.out.println ( "standing ready to wait" + Thread.currentThread () getName ().);
            latch.await();
            System.out.println ( "heard issuing the order to start the race" + Thread.currentThread () getName ().);
        } catch (InterruptedException e) {
            e.printStackTrace ();
        }
    }, "t1").start();

    // Record number minus one is not prepared 
    Thread.sleep (1000 );
    latch.countDown();


    new Thread(()->{
        try {
            System.out.println ( "standing ready to wait" + Thread.currentThread () getName ().);
            latch.await();
            System.out.println ( "heard issuing the order to start the race" + Thread.currentThread () getName ().);
        } catch (InterruptedException e) {
            e.printStackTrace ();
        }
    }, "t2").start();

    // Record number minus one is not prepared 
    Thread.sleep (1000 );
    latch.countDown();

} 

The results:

for the first time

Ready place waiting t1
Ready t2 still waiting
to hear issuing the order to start the race t1
heard issuing the order to start the race t2

  the second time

Ready place waiting t1
Ready t2 still waiting
to hear issuing the order to start the race t2
heard issuing the order to start the race t1

 

 

Second latch.countDown that everything is ready (when), then start issuing the order, then began to start two players, who should finish are determined by their ability

Summary: racing use software commonly used in pressure measurement, while the number of open test thread, and enters a wait state, when all the threads ready, while performing business, to achieve high concurrency testing

 

2. The same is the long-distance race, since there are also naturally ranking tournament, only one player to finish in the final end of the game announced

public static void main(String[] args) throws InterruptedException {
    final CountDownLatch latch = new CountDownLatch(2);

    new Thread(()->{

        try {
            System.out.println ( "trying to run" + Thread.currentThread () getName ().);
             // finish the course takes two seconds 
            Thread.sleep (2000L );
            System.out.println ( "end run to reach the end" + Thread.currentThread () getName ().);
            latch.countDown();
        } catch (InterruptedException e) {
            e.printStackTrace ();
        }

    }, "t1").start();

    new Thread(()->{

        try {

            System.out.println ( "trying to run" + Thread.currentThread () getName ().);
             // finish the course takes five seconds 
            Thread.sleep (5000L );
            System.out.println ( "end run to reach the end" + Thread.currentThread () getName ().);
            latch.countDown();
        } catch (InterruptedException e) {
            e.printStackTrace ();
        }


    }, "T2" ) .start ();
     // 0.1 seconds just sleep that the print bit string no practical effect 
    the Thread.sleep (100 );
    System.out.println ( "wait for the last player to finish" );
    latch.await();
    System.out.println ( "everyone has to finish the end of the game" );

}

operation result:
Trying to run t1
Trying to run t2
Waiting for the last player to finish
End run to reach the terminal t1
Run to reach the terminal end of t2
End of the game everyone has to finish

latch.await () will block the main thread until the last person to finish, before announcing the end of the game

Summary: This example can be used to execute multiple threads simultaneously, but a final report after completion of thread execution results, avoid polling query whether all threads are executed, of course, in addition there are many implementations, such as it is used to resolve this CompletableFuture kind of problem, this article is not too much to explain

 

Source analysis method :

1. Constructors CountDownLatch (int count), have knowledge of the AQS is very easy to understand the code below is actually a set of state 

public CountDownLatch(int count) {
    if (count < 0) throw new IllegalArgumentException("count < 0");
    this.sync = new Sync(count);
}
// the AQS state set value COUNT 
Sync ( int COUNT) {
    setState(count);
}
protected final void setState(int newState) {
    state = newState;
}

 

2. blocking method latch.await ()

AQS use shared lock principle, if the AQS state property is not 0, then the current thread node into the AQS wait queue and wait mode is set to shared mode (with the first spread in unlocking achieve shared), and blocks the current thread of execution

类 CountDownLatch 
public void await() throws InterruptedException {
    sync.acquireSharedInterruptibly(1);
}

Class CountDownLatch.Sync
public  Final  void acquireSharedInterruptibly ( int Arg)
             throws InterruptedException {
     IF (Thread.interrupted ())
         the throw  new new ; InterruptedException ()
     // The following piece of code can be seen as the initial count state attempt to acquire the lock
     // the case if the state is not changed (the countDown () will speak on how to change) is bound to perform doAcquireSharedInterruptibly (Arg) 
    IF (tryAcquireShared (Arg) <0 )
        doAcquireSharedInterruptibly (Arg);
}
// attempt to acquire synchronization lock 
protected  int tryAcquireShared ( int Acquires) {
     return (getState () == 0). 1: -1? ;
}
// Get synchronization lock 
Private  void doAcquireSharedInterruptibly ( int Arg)
         throws InterruptedException {
     // new node waits 
    Final the Node Node = addWaiter (Node.SHARED);
     Boolean failed = to true ;
     the try {
         for (;;) {
             Final the Node P = Node .predecessor ();
             IF (P == head) {
                 int R & lt = tryAcquireShared (Arg);
                 IF (R & lt> = 0 ) {
                     //Node and the node of the heads is shared mode waiting mode (shared mode concept can be found in the article AQS) 
                    setHeadAndPropagate (Node, R & lt);
                    p.next = null; // help GC
                    failed = false;
                    return;
                }
            }
            // blocks the current thread 
            IF (shouldParkAfterFailedAcquire (the p-, the Node) &&
                parkAndCheckInterrupt ())
                throw new InterruptedException();
        }
    } finally {
        if (failed)
            cancelAcquire(node);
    }
}

 

3.latch.countDown () counting method

AQS using the principle of shared lock released state = 0 when the count of the wait queue thread calls a chain (propagation) of the wake

类 CountDownLatch 
public void countDown() {
        sync.releaseShared(1);
    }

Class CountDownLatch.Sync
// shared locks are released (not necessarily just tried successfully released) 
public  Final  Boolean releaseShared ( int Arg) {
     // try to release shared locks when the count equals 0 tryReleaseShared (arg) is equal to true 
    IF (tryReleaseShared (Arg)) {
        doReleaseShared();
        return true;
    }
    return false;
}
// try to release shared locks 
protected  Boolean tryReleaseShared ( int Releases) {
     // of Decrement COUNT; Signal When Transition to ZERO 
    for (;;) {
         int C = getState ();
         IF (C == 0 )
             return  to false ;
         // count Save a 
        int NEXTC-C =. 1 ;
         // the atomic state = nextc then returns NEXTC i.e. atomic operation state is equal to 0 
        iF (compareAndSetState (C, NEXTC))
             return NEXTC == 0 ;
    }
}
// release the shared lock this period will not speak in detail to do is share lock release
 // if the current node waitStatus = -3 then continue to spread to the next node 
 // Caught waitStatus = -3 skip continues to spread to the next node, then reached wake up threads on all nodes 
Private  void doReleaseShared () {
     for (;;) {
        Node h = head;
        if (h != null && h != tail) {
            int ws = h.waitStatus;
            if (ws == Node.SIGNAL) {
                if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
                    continue;            // loop to recheck cases
                unparkSuccessor(h);
            }
            else if (ws == 0 &&
                     !compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
                continue;                // loop on failed CAS
        }
        if (h == head)                   // loop if head changed
            break;
    }
}

 

Summary :

CountDownLatch underlying principle of using a AQS, if mastered AQS CountDownLatch principle is easy to understand

Guess you like

Origin www.cnblogs.com/xieyanke/p/12165185.html