Java - 在COUNTDOWNLATCH中计数

时间:2012-11-27 20:09:34

标签: java countdownlatch

在运行每个线程时,为什么countdown.getCount()总是打印'3',即使前一个线程已经调用了countdown.countDown()并将Latch Count减少了1?

我很遗憾Java知道Latch Count已达到0,因此它可以释放所有3个线程。

import java.util.concurrent.CountDownLatch;

class b {
static final CountDownLatch countdown = new CountDownLatch(3);

public static void main(String[] args) {

    for (int i = 0; i < 3; ++i) {
        Thread t = new Thread() {
            public void run() {
                System.out.printf("Starting on %d other threads.\n",
                        countdown.getCount());
                countdown.countDown();
                System.out.printf("new on %d other threads.\n",
                        countdown.getCount());
                try {
                    countdown.await(); // waits until everyone reaches this
                                        // point
                    // System.out.println("Go again : "
                    // +countdown.getCount());
                } catch (Exception e) {
                }
            }
        };
        t.start();

    }
    System.out.println("Go");
}

}

2 个答案:

答案 0 :(得分:2)

你并行启动3个线程。根据它们开始的速度,它们都可以在任何线程设法调用countDown()之前打印“3”(至少对于“开始......”行)。但是,“new on ...”行应打印出2到0之间的某些数字范围。

答案 1 :(得分:0)

绝对有可能所有三个线程打印&#34;从3开始...&#34;当线程并行运行时,计数不会改变,直到线程执行countDown()。为了真正理解发生了什么,我建议您在print语句之前添加System.nanoTime()和线程名称,如下所示:

...
Thread t = new Thread("Thread-" + i) { 
...
System.out.printf("%d> %s: Starting on %d other threads.\n", System.nanoTime(), getName(), countdown.getCount());
countdown.countDown();
System.out.printf("%d> %s: new on %d other threads.\n", System.nanoTime(), getName(), countdown.getCount());

有时您会得到如下所示的输出,这可能会让您觉得Thread-2无视Thread-1对countDown的调用:

1407489646569321000> Thread-0: Starting on 3 other threads.
1407489646569324000> Thread-1: Starting on 3 other threads.
1407489646602463000> Thread-1: new on 1 other threads.
1407489646569513000> Thread-2: Starting on 3 other threads.
1407489646602107000> Thread-0: new on 2 other threads.
1407489646603275000> Thread-2: new on 0 other threads.

然而,事实并非如此,我们可以通过查看时间戳来验证正确的操作顺序。输出中的混淆是由于线程调度中固有的不可预测性,这取决于哪个线程获得cpu splice。

话虽如此,根据线程安排或延迟,它们可能并不总是打印3。例如,尝试按如下所示放置Thread.sleep(..):

public static void main(String[] args) throws Exception {
    for (int i = 0; i < 3; ++i) {
        Thread t = new Thread() {
            public void run() {
                 /* As before */
            }
        };
        t.start();
        Thread.sleep(100); // Artificial Delay
    }
}

现在你应该看到不同的结果,如下所示:!

1407490223575404000> Thread-0: Starting on 3 other threads.
1407490223607879000> Thread-0: new on 2 other threads.
1407490223676233000> Thread-1: Starting on 2 other threads.
1407490223676818000> Thread-1: new on 1 other threads.
1407490223777623000> Thread-2: Starting on 1 other threads.
1407490223778221000> Thread-2: new on 0 other threads.

在内部,CountDownLatch维护一个先进先出等待队列(参见.GrathQueuedSynchronizer)。计数值是同步的,等待线程仅在计数变为0或其他线程中断等待线程时释放。这是锁存器用于跟踪所有线程何时到达锁存器的机制。

如果您有兴趣了解测试环境中的闩锁,请结帐http://razshahriar.com/2014/08/testing-asynchronous-code-in-java-with-countdownlatch/ 希望这有助于澄清您对计划行为的调查。