"Java Concurrency Programming Combat"-"J.U.C": Countdownlatch

Source: Internet
Author: User

The last blog post ("Java Concurrency Programming Combat"-"J.U.C": cyclicbarrier) LZ introduced Cyclicbarrier. Cyclicbarrier describes "allowing a group of threads to wait on each other until a public barrier point is reached before the next task is performed." And Countdownlatch has a little resemblance to it: Countdownlatch describes "it allows one or more threads to wait until a set of actions are performed in another thread." This is illustrated in the JDK API:

Initializes the countdownlatch with the given count. Because the countdown () method is called, the await method is blocked until the current count reaches 0. After that, all the waiting threads are freed, and all subsequent calls to await are returned immediately. This behavior occurs only once-the count cannot be reset. If you need to reset the count, consider using Cyclicbarrier.

Countdownlatch is a universal synchronization tool that has many uses. Countdownlatch, which counts 1 initialized, is used as a simple on/Guan, or Portal: All threads that call await are waiting at the entrance until a thread that calls Countdown () opens the portal. N-initialized Countdownlatch can cause a thread to wait until N threads complete an operation, or to wait until an operation completes N.

A useful feature of Countdownlatch is that it does not require a thread that calls the countdown method to wait until the count arrives 0 o'clock, and before all threads can pass, it simply prevents any thread from continuing through an await.

Although Countdownlatch and cyclicbarrier are similar, there are some differences:

1, the role of Countdownlatch is to allow 1 or n threads to wait for other threads to complete execution, while the cyclicbarrier is to allow n threads to wait for one another.

2, Countdownlatch counter cannot be reset, Cyclicbarrier counter can be reset after use, so it is called a circular barrier.

Countdownlatch Analysis

The Countdownlatch structure is as follows:


It can be seen from the Countdownlatch rely on sync, in fact, countdownlatch internal use of a shared lock to achieve (internal sync implementation can be seen). Its constructor is as follows:

Countdownlatch (int count): Constructs a countdownlatch initialized with the given count.

public Countdownlatch (int count) {        if (count < 0) throw new IllegalArgumentException ("Count < 0");        This.sync = new sync (count);    }

The following source code proves that the Countdownlatch internal is implemented with shared locks:

Private static final class Sync extends Abstractqueuedsynchronizer {        private static final long Serialversionuid = 4982 264981922014374L;        protected int tryacquireshared (int acquires) {            /** omit source code **/        }        protected Boolean tryreleaseshared (int Releases) {           /** omit source code **/        }    }

Countdownlatch provides an await method to implement:

Await (): Causes the current thread to wait until the latch is counted down to 0, unless the thread is interrupted.

Await (long timeout, timeunit unit): Causes the current thread to wait until the latch is counted down to 0, unless the thread is interrupted or the specified wait time is exceeded.

public void await () throws Interruptedexception {        sync.acquiresharedinterruptibly (1);    }

Await the Acquiresharedinterruptibly method for internal call Sync:

Public final void acquiresharedinterruptibly (int arg)            throws interruptedexception {        //thread interrupted, Throws Interruptedexception exception        if (thread.interrupted ())            throw new Interruptedexception ();        if (tryacquireshared (ARG) < 0)            doacquiresharedinterruptibly (ARG);    }

The function of acquiresharedinterruptibly () is to acquire a shared lock. Throws a Interruptedexception exception if a thread break occurs during the acquisition of a shared lock. Otherwise, the Tryacquireshared method is used to attempt to acquire a shared lock. If the return is successful, the Doacquiresharedinterruptibly method is called.

Tryacquireshared Source:

protected int tryacquireshared (int acquires) {            return (getState () = = 0)? 1:-1;        }

The Tryacquireshared method was rewritten by Countdownlatch and his main role was to try to acquire the lock. GetState = = 0 means that the lock is in the available state return 1 otherwise returns-1; When Tryacquireshared returns-1 acquires the lock failure, the call doacquiresharedinterruptibly acquires the lock:

private void doacquiresharedinterruptibly (int arg) throws Interruptedexception {//create current thread (shared lock) node            Final node node = addwaiter (node.shared);            Boolean failed = true; try {for (;;)                    {//Gets the previous node of the current node, final nodes P = node.predecessor (); If the current node is a CLH column header, try to acquire the lock if (p = = head) {//get lock int r = Trya                        Cquireshared (ARG);                            if (r >= 0) {setheadandpropagate (node, r); P.next = null;                            Help GC failed = false;                        Return }}//If the current node is not a CLH column header, the current thread waits until the lock is acquired (Shouldparkafterfailedacq Uire (p, node) && parkandcheckinterrupt ()) throw new Interruptedexcep tion ();            }} finally {if (failed) cancelacquire (node); }        }

The method of the method, the previous blog has been described, please refer to: "Java Concurrency Programming Combat"-"J.U.C": Reentrantlock two Lock method analysis, "Java Concurrent programming Practical Combat"-"J.U.C": Semaphore.

Countdownlatch, in addition to providing an await method, also provides countdown (), which Countdown describes as "decrements the latch count, and releases all waiting threads if the count reaches 0." The source code is as follows:

public void Countdown () {        sync.releaseshared (1);    }

Countdown internally calls the Releaseshared method to release the thread:

Public final Boolean releaseshared (int arg) {        //tries to free the thread if release is released and calls Doreleaseshared () if        (tryreleaseshared (ARG)) {            doreleaseshared ();            return true;        }        return false;    }

Tryreleaseshared, at the same time, was rewritten by Countdownlatch:

protected Boolean tryreleaseshared (int releases) {for        (;;) {            //Get lock status            int c = getState ();            c = = 0 return directly, release the lock successfully            if (c = = 0)                return false;            Calculates the new "lock counter"            int nextc = c-1;            Update lock status (counter)            if (Compareandsetstate (c, NEXTC))                return NEXTC = = 0;        }    }

Summarize:

The Countdownlatch is implemented internally through a "shared lock". When you create a countdownlatch, you pass a count parameter of type int, which is the initial value of the lock state, which indicates how many threads the shared lock can be fetched at the same time. When a thread calls the await method, it first determines whether the state of the lock is in the available state (the condition is count==0), and if the shared lock gets a shared lock, it waits until it gets. When a thread calls the Countdown method, the counter count–1. When the count parameter is initialized when the Countdownlatch is created, it is necessary to have a count thread call the countdown method to make the counter count equals 0, and the lock is freed before the thread that waits before it continues to run.

Instance

An employee's meeting will only open an account when everyone expires. We initialize 3 participants, then the count of Countdownlatch should be 3:

public class Conference implements runnable{    private final countdownlatch countdown;        public Conference (int count) {        countdown = new Countdownlatch (count);    }        /**     * Attendees arrive, call the arrive method, reach a Countdownlatch call countdown method, lock Counter-1     * @author: Chenssy     * @data: September 6, 2015     *     * @param name     *    /public void arrive (String name) {        System.out.println (name + "arrive ...");        Call Countdown () lock Counter-1        countdown.countdown ();        System.out.println ("also" + countdown.getcount () + "not arrived ...");        @Override public    Void Run () {        System.out.println ("Prepare to meet, total number of meeting attendees:" + countdown.getcount ());        Call await () to wait for all participants to arrive at        try {            countdown.await ();        } catch (Interruptedexception e) {        }        SYSTEM.OUT.PRINTLN ("All personnel have arrived, the meeting begins ...");}    

Participants participater:

public class Participater implements runnable{    private String name;    Private Conference Conference;        Public Participater (String name,conference Conference) {        this.name = name;        this.conference = conference;    }    @Override public    Void Run () {        conference.arrive (name);}    }

Test:

public class Test {public    static void Main (string[] args) {        //start room thread, waiting for attendees to attend conference        Conference Conference = new Conference (3);        New Thread (Conference). Start ();                for (int i = 0; i < 3; i++) {            Participater participater = new Participater ("chenssy-0" + I, conference);            Thread thread = new Thread (participater);            Thread.Start ();}}}    

Operation Result:

Prepare for the meeting, the total number of participants: 3chenssy-01 arrived .... 2 have not arrived ... chenssy-00 arrived ... 1 have not arrived ... chenssy-02 arrived ... There are still 0 not arriving ... All the people have arrived and the meeting has begun .....

Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

Java concurrency Programming Combat-"J.U.C": Countdownlatch

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.