Java Concurrency In Practice中的CountDownLatch示例

时间:2014-03-08 22:32:26

标签: java multithreading concurrency

我正在阅读Java Concurrency In Practice一书,并且遇到了CountDownLatch。

以下是给出的示例:

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;
    }
}

以下是其解释:

  代码清单5.11中的TestHarness说明了锁存器的两种常见用法。   TestHarness创建了许多运行给定任务的线程   同时。它使用两个锁存器,一个“起始门”和一个“结束   闸门“。起始门的初始值为1;   结束门的初始化计数等于worker的数量   线程。每个工作线程做的第一件事是等待   起跑门;这可以确保它们都不会开始工作直到   他们都准备开始了。每个人做的最后一件事就是倒计时   在结束门上;这允许主线程有效地等待   直到最后一个工作线程完成,所以它可以   计算经过的时间。

我是Java多线程的新手,所以我无法理解给出的解释以及该程序的工作原理。

这是什么意思 -

  

每个工作线程做的第一件事是等待起始门;   这可以确保他们都没有开始工作,直到他们都准备好了   开始。每个人做的最后一件事是倒数结束门;   这允许主线程有效地等待直到最后一个   工作线程已完成,因此可以计算经过的时间。

以及这段代码如何正常工作:

Thread t = new Thread() {

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

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

请帮助我理解这个概念。

4 个答案:

答案 0 :(得分:4)

这段代码

Thread t = new Thread() {

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

设置所需的所有线程。每个线程将等待startGate被“打开”,即。它的计数为0.当线程完成执行Runnable时,即。 run()返回,他们将倒计时endGate。这就是这个

  

每个工作线程做的第一件事是等待起始门;   这可以确保他们都没有开始工作,直到他们都准备好了   开始。每个人做的最后一件事就是在结束门上倒数;

的装置。

设置完所有线程后,执行此代码。

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

当前线程倒计时startGate,允许所有其他线程开始执行其Runnable,即。 task.run()。然后等待endGate上的(块)倒计数到0.此时,它计算所花费的时间并返回该值。这就是这个

  

这允许主线程有效地等待直到最后一个   工作线程已完成,因此可以计算经过的时间。

装置

答案 1 :(得分:2)

确实不是很清楚 你的实际问题是什么,或者只要不清楚你已经知道什么就应该解释代码。

但是,这里使用的概念并不复杂,通过删除错误处理并使用内联注释指出重要部分,它可能已经变得更加清晰:

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();

答案 2 :(得分:1)

startGate最初设置为1,因此所有线程都会等到计数结束。

endGate被初始化为我们计划使用的线程数,所以它会等到所有线程都通过结束门之后再报告所花费的时间。

// 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();

答案 3 :(得分:0)

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();
}

}