简体   繁体   中英

CountDownLatch example in Java Concurrency In Practice

I am going through the Java Concurrency In Practice book and came across the CountDownLatch.

Below is the example given:

public class TestHarness {
    public long timeTasks(int nThreads, final Runnable task)
        throws InterruptedException {

        final CountDownLatch startGate = new CountDownLatch(1);
        final CountDownLatch endGate = new CountDownLatch(nThreads);

        for (int i = 0; i < nThreads; i++) {
            Thread t = new Thread() {

                public void run() {
                    try {
                        startGate.await();
                        try {
                            task.run();
                        } finally {
                            endGate.countDown();
                        }
                    } catch (InterruptedException ignored) { }
                }
            };
            t.start();
        }
        long start = System.nanoTime();
        startGate.countDown();
        endGate.await();
        long end = System.nanoTime();
        return end-start;
    }
}

and here is its explanation:

TestHarness in Listing 5.11 illustrates two common uses for latches. TestHarness creates a number of threads that run a given task concurrently. It uses two latches, a "starting gate" and an "ending gate". The starting gate is initialized with a count of one; the ending gate is initialized with a count equal to the number of worker threads. The first thing each worker thread does is wait on the starting gate; this ensures that none of them starts working until they all are ready to start. The last thing each does is count down on the ending gate; this allows the master thread to wait efficiently until the last of the worker threads has finished, so it can calculate the elapsed time.

I am new to Java multithreading so I am not able to understand the explanation given and how this program works.

What does it mean that -

The first thing each worker thread does is wait on the starting gate; this ensures that none of them starts working until they all are ready to start. The last thing each does is count down on the ending gate; this allows the master thread to wait efficiently until the last of the worker threads has finished, so it can calculate the elapsed time.

and how this piece of code works exactly:

Thread t = new Thread() {

    public void run() {
        try {
            startGate.await();
            try {
                task.run();
            } finally {
                endGate.countDown();
            }
        } catch (InterruptedException ignored) { }
    }
};

and

long start = System.nanoTime();
startGate.countDown();
endGate.await();
long end = System.nanoTime();
return end-start;

Please help me in understanding this concept.

This piece of code

Thread t = new Thread() {

    public void run() {
        try {
            startGate.await();
            try {
                task.run();
            } finally {
                endGate.countDown();
            }
        } catch (InterruptedException ignored) { }
    }
};

sets up all the threads that will be needed. Each thread will wait on the startGate to be "opened", ie. its count to go to 0. When the threads are done executing the Runnable , ie. run() returns, they will countdown the endGate . That's what this

The first thing each worker thread does is wait on the starting gate; this ensures that none of them starts working until they all are ready to start. The last thing each does is count down on the ending gate;

means.

When all the threads are set up, this code is executed.

long start = System.nanoTime();
startGate.countDown();
endGate.await();
long end = System.nanoTime();
return end-start;

The current thread counts down startGate , which allows all the other threads to begin executing their Runnable , ie. task.run() . It then awaits (blocks) on the endGate to be count down to 0. At this point, it calculates how long that took and returns that value. That's what this

this allows the master thread to wait efficiently until the last of the worker threads has finished, so it can calculate the elapsed time.

means

It is indeed not perfectly clear what your actual question is, or how the code should be explained as long as it is not clear what you already know.

However, the concepts used here are not so complicated, and it might already become clearer by removing the error handling and pointing out the important parts with in-line comments:

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

    // This will create and start a new thread
    // that executes the code in the "run" method
    Thread t = new Thread() {
        public void run() {

            // Wait until this thread gets the start signal
            startGate.await();

            // Perform some arbitrary work
            task.run();

            // Notify everybody that this thread has finished his work
            endGate.countDown();
        }
    };
    t.start(); 
}

// Give all threads the start signal: Counting down
// where will cause the latch to reach the value 0,
// and every thread that is waiting at "startGate.await()"
// will proceed his work
startGate.countDown();

// Wait here until all threads have called "endGate.countDown()".
endGate.await();

The startGate is set initially to 1 so all threads will wait until it is counted down.

The endGate is initialised to the number of threads we plan to use so it will wait until all threads have passed the end gate before it reports the time taken.

// Take a note of the time.
long start = System.nanoTime();
// Start all of the threads running - they all wait for this signal by calling startGate.await().
startGate.countDown();
// Wait for all threads to complete - they record their finish with endGate.countDown().
endGate.await();
// Note the time.
long end = System.nanoTime();
package com.sample.thread;

import java.util.concurrent.CountDownLatch;

public class CDLExample {

private static CountDownLatch latch;

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

    new Thread("main") {
        public void run() {
            try {
                latch.await();
                System.out
                        .println("\nStarting Main thread as all other thread is started");
                System.out.println("CountDownLatch demonstrated: "
                        + Thread.currentThread().getName());
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }.start();

    new Thread("first") {
        public void run() {
            System.out.println("Print Odd Number: "
                    + Thread.currentThread().getName());
            try {
                for (int i = 1; i < 20; i = i + 2) {
                    System.out.print(i + " ");
                    Thread.sleep(50);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            latch.countDown();
        }
    }.start();

    new Thread("second") {
        public void run() {
            try {
                Thread.sleep(1000);
                System.out.println("\nPrint Even Number: "
                        + Thread.currentThread().getName());

                for (int i = 2; i < 20; i = i + 2) {
                    Thread.sleep(50);
                    System.out.print(i + " ");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            latch.countDown();
        }
    }.start();
}

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM