What is CountDownLatch?

CountDownLatch, commonly known as a latching or counter, is a multithreaded synchronization tool that belongs to the AQS system.

It is often used to have a coordinating thread wait for a group of worker threads to “complete work” or “meet certain conditions” to continue.

However, it is also possible to use cyclicbarriers to make a group of threads all reach the specified point before executing. However, cyclicbarriers are not as simple and reusable as cyclicbarriers, so we tend to use cyclicbarriers directly when a group of threads are waiting for themselves.

How does CountDownLatch work?

The boss has a safe, in order to ensure security, designated 3 cronies with the password. The boss can open the safe only when three cronies enter the password at the same time.

When the boss says he wants to withdraw money and run away, open the lock. So the confidant quickly input the password.

image-20210618155056132
A simple way

We can do this by telling the boss to use int as a counter and loop through it:

private static void rr(a) {

    System.out.println(Boss: I need to pick the lock.);

    AtomicInteger count = new AtomicInteger(3);

    for (int i = 0; i < count.get(); i++) {

        new Thread(new Runnable() {

            @Override

            public void run(a) {

                count.decrementAndGet();

            }

        }).start();

    }

    while(count.get() ! =0) {

        System.out.println(Boss: Hurry up, you fools!);

        Thread.sleep(1000);

    }

    System.out.println("Boss: Take money to run away, cronies sold.");

}

Copy the code

But how many problems are there?

  • Simple ints have concurrency problems, and we can either use volatile or atomic classes

  • The boss is always bugging him. If he needs to be quiet, let him sleep for a while.

    But the lock of the safe in the first input, it is necessary to complete and open all within the limited time, that the boss slept how to do.

    Is there any other means of thread communication needed?

The coordinating thread waits for the worker thread

Lieutenant 1: Report to the boss, we found a good thing. Can enter password safely already, a few people won’t be deranged

Confidant 2: I will inform you as soon as I input everything.

Confidant 3: It also supports not finishing within a limited time, and it will notify you of the problem. (OS: Maybe one of us got killed).

Boss: Good thing, come out and show me.

public class CountDownLatchDemo {

    public static void main(String[] args) {

        System.out.println(Boss: I need to pick the lock.);

        // Specify 3 associates

        CountDownLatch latch = new CountDownLatch(3);

        for (int i = 0; i < 3; i++) {

            new Thread(new Follower(latch)).start();

        }

        try {

            latch.await(1, TimeUnit.MINUTES);

        } catch (InterruptedException e) {

            System.out.println("Boss: are they all idiots? This input failed.");

        }

        System.out.println("Boss: Take money to run away, cronies sold.");

    }



    private static class Follower implements Runnable {

        private CountDownLatch latch;

        public Follower(CountDownLatch latch) {

            this.latch = latch;

        }

        @Override

        public void run(a) {

            System.out.println("Confidant: Enter the password ing");

            latch.countDown();

            System.out.println("Cronies: Report to boss, typing done.");

        }

    }

}

Boss: I want to pick the lock

Confidant: Enter the password ing

Confidant: report boss, input complete

Confidant: Enter the password ing

Confidant: report boss, input complete

Confidant: Enter the password ing

Confidant: report boss, input complete

Boss: take money to run away, close friend sold

Copy the code
Wait for each other

Squeezed by their bosses, cronies have taken different paths.

Confidant OS: The boss will sell us eventually. Let’s turn ourselves into masters and take the money.

image-20210618162002818
private static void cycleCountDown(a) throws InterruptedException {

    System.out.println("Cronies: Success or death !!!!");

    CountDownLatch latch = new CountDownLatch(3);

    for (int i = 0; i < 3; i++) {

        new Thread(new MyFollower(latch)).start();

    }

    Thread.sleep(1000);

}



private static class MyFollower implements Runnable {

    private CountDownLatch latch;



    public MyFollower(CountDownLatch latch) {

        this.latch = latch;

    }



    @Override

    public void run(a) {

        System.out.println("Confidant: Enter the password ing");

        latch.countDown();

        System.out.println("Confidant: I've got it. Wait for you.");

        try {

            latch.await(1, TimeUnit.MINUTES);

        } catch (InterruptedException e) {

            System.out.println("OS: Do you want the money or not?");

        }



        System.out.println("Cronies: become!!!!!");

    }

}

Cronies: not successful then become benevolence!!!!!

Confidant: Enter the password ing

Confidant: Enter the password ing

Confidant: I've got it. Wait for you.

Confidant: I've got it. Wait for you.

Confidant: Enter the password ing

Confidant: I've got it. Wait for you.

Confidant: become!!!!!

Confidant: become!!!!!

Confidant: become!!!!!

Copy the code

How is CountDownLatch implemented?

The main methods are as follows, very succinct:

image-20210618162645530

Most key or Sync inner classes, implements the AbstractQueuedSynchronizer (AQS).

Here no longer shows AQS content, will be simple, in-depth study see: AbstractQueuedSynchronizer (AQS) : the cornerstone of concurrent tool (juejin. Cn)

CountDownLatch holds an internal instance of Sync: private final Sync Sync;

To build this Sync, specify the number at construct time:

public CountDownLatch(int count) {

    if (count < 0throw new IllegalArgumentException("count < 0");

    this.sync = new Sync(count);

}

Copy the code

Once Sync receives this count, those of you who know AQS will immediately understand that this is to give the state field its true meaning: the amount remaining to meet the specified condition.

private static final class Sync extends AbstractQueuedSynchronizer {



    Sync(int count) {

        setState(count);

    }



    int getCount(a) {

        return getState();

    }

}

Copy the code
How to keep the boss waiting without nagging?

Await has two overloaded methods:

public void await(a) throws InterruptedException {

    sync.acquireSharedInterruptibly(1);

}

public boolean await(long timeout, TimeUnit unit) throws InterruptedException {

    return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));

}

Copy the code

Here is the category of AQS:

image-20210618164503588

The previous step is what Sync needs to implement.

Because the value of state needs to be judged, but this count is given in the subclass, so the operation method is also in the subclass:

Only counting state = 0 can proceed.

 private static final class Sync extends AbstractQueuedSynchronizer {

     protected int tryAcquireShared(int acquires) {

        return (getState() == 0)?1 : -1;

    }

 }

Copy the code

If it doesn’t go to zero, tell the boss to wait. AQS maintains a queue of resources that extends to subclasses, waiting for getState() == 0 to occur.

image-20210618164954204

Confidant: since the boss does not compare than, must hurriedly input password, otherwise timeout again want noisy.

Close -; Close -; Close -. Done!!

Enter your password and notify your boss
public void countDown(a) {

    sync.releaseShared(1);

}

Copy the code

Look, look, AQS again:

image-20210618165537524

If it is a simple int, it is easy to have concurrency problems, resulting in input confusion, and then finally have to be punished by the boss.

So you need a reliable way: CAS + volatile (state is volatile by nature)

private static final class Sync extends AbstractQueuedSynchronizer {

    protected boolean tryReleaseShared(int releases) {

        // Decrement count; signal when transition to zero

        for (;;) {

            int c = getState();

            if (c == 0)

                // It has been completed and cannot be notified again, one-time

                return false;

            int nextc = c - 1;

            if (compareAndSetState(c, nextc))

                // Just done, returns true for notification.

                return nextc == 0;

        }

    }

}

Copy the code

Return true to wake up the boss: boss boss, typing done!!

image-20210618170001285

conclusion

In fact, it omitted a lot of AQS, which is complicated and quite complicated. If you don’t know what to say, read these two articles

  • The cornerstone of AbstractQueuedSynchronizer (AQS) : concurrent tool (juejin. Cn)
  • AQS Condition source code parsing (juejin. Cn)

But there’s a problem. It’s disposable.

Parallel spacetime 1:

Boss: this trifle can only use once have a fart use, I this is safe, not shoot rocket!! 😡 😡 😡 😡

CountDownLatch: I can shoot rockets, too. After all, rocket launches are controlled by a few chief engineers

Close: 😖 😖 😖 😖

Parallel spacetime 2:

Close friends: this thing how bad, how to let the boss short-term not discover 😓😓😓😓

CyclicBarrier: Heard someone on cue me?