This section describes the use of latches, using CountDownLatch as an example to control processes. The sample code goal is to have all threads create and wait until they are all created and then execute together, testing how long it takes to execute tasks concurrently. But based on actual tests, the results were found to be wrong. For the record.

P79 uses CountDownLatch in timing tests to start and stop thread sample code, add output and comments
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(a) {
                    try {
                        System.out.println(Thread.currentThread().getId() + " await");
                        startGate.await();
                        try {
                            System.out.println(Thread.currentThread().getId() + " run");
                            task.run();
                        } finally{ endGate.countDown(); }}catch (InterruptedException ignored) {
                    }
                }
            };
            t.start();
        }
        long start = System.nanoTime();
        // After all threads are countdown, startGate status is set to 0, and all threads are ready
        startGate.countDown();
        endGate.await();
        long end = System.nanoTime();
        returnend - start; }}Copy the code
perform
public class App {
    public static void main(String[] args) throws Exception {
        System.out.println("time:" + new TestHarness().timeTasks(5, () -> {}));
    }
}
Copy the code
The output
16 run
17 await
17 run
19 await
19 run
18 await
18 run
15 await
15 run
time:9583200
Copy the code

Obviously not as expected

parsing

The problem is that when the main thread startgate.countdown () executes, the thread created by the previous for loop may not have yet executed startgate.await (), making it impossible to release all threads at the same time.

This can be resolved using the CyclicBarrier class

class FixedTestHarness {
    public long timeTasks(int nThreads, final Runnable task) throws InterruptedException {
        // final CountDownLatch startGate = new CountDownLatch(1);
        final CountDownLatch endGate = new CountDownLatch(nThreads);
        final CyclicBarrier cyclicBarrier = new CyclicBarrier(nThreads);

        for (int i = 0; i < nThreads; i++) {
            Thread t = new Thread() {
                public void run(a) {
                    try {
                        System.out.println(Thread.currentThread().getId() + " await");
                        // startGate.await();
                        cyclicBarrier.await();
                        try {
                            System.out.println(Thread.currentThread().getId() + " run");
                            task.run();
                        } finally{ endGate.countDown(); }}catch (Exception ignored) {
                    }
                }
            };
            t.start();
        }
        long start = System.nanoTime();
        // startGate.countDown();
        endGate.await();
        long end = System.nanoTime();
        returnend - start; }}Copy the code

The results of

16 await
15 await
17 await
18 await
19 await
19 run
18 run
17 run
15 run
16 run
time:5743800
Copy the code