为什么 java 中的 Countdownlatch 不能在给定的锁存器计数时停止?

why can't Countdownlatch in java stops at given latch count?

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class Processor implements Runnable {
    private CountDownLatch latch;

    public Processor(CountDownLatch latch) {
        this.latch = latch;
    }

    public void run() {
        System.out.println("Started.");

        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        latch.countDown();
    }
}
// -----------------------------------------------------

public class App {

    public static void main(String[] args) {

        CountDownLatch latch = new CountDownLatch(5); // coundown from 5 to 0

        ExecutorService executor = Executors.newFixedThreadPool(2); // 2 Threads in pool

        for(int i=0; i < 10; i++) {
            executor.submit(new Processor(latch)); // ref to latch. each time call new Processes latch will count down by 1
        }

        try {
            latch.await();  // wait until latch counted down to 0
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

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

}

输出:

开始 开始 开始 开始 开始 开始 开始 完成` 开始 开始 开始

在上面的代码中 "Completed" 应该在 6 次后打印 "Started" 因为锁存器倒数到 5 - 0,为什么它总是第 7 次或第 8 次?我理解错了吗?

因此,CountDownLatch 不保证一旦倒计时进入 0。因此,当 Count Down 锁存器倒计时到 0 时会发生什么,这意味着现在父线程可以恢复其工作,但这并不意味着它会在那里获得 CPU。所以,它可以恢复并不意味着CPU调度父线程倒计时到0。如果还有其他线程,那么它们是否有可能在父线程之前执行。 在你的情况下,它确保它不会执行 before 5 时间打印 Started 但它确实 ensure 它会打印 5Started 后为 exactly。您可能还会在代码的某个执行过程中观察到 Completed 在所有 Started 打印结束时打印。

您的线程池大小为 2,您的 Processor 线程执行需要 3 秒。

  • 前两个 Processors 线程启动,都打印 Started 并在 3 秒后完成。
  • 然后接下来的两个开始,它们再次打印 Started 并在 3 秒后完成。
  • 然后开始另外两个(第 5 个和第 6 个),打印 Started 并在 3 秒后其中一个(或两个)完成。在这一点上,有几件事情将大致同时发生(所以顺序是随机的):

    1. 主线程恢复并打印Completed
    2. 第 7 个 Processor 线程启动并打印 Started
    3. 第 8 个 Processor 线程启动并打印 Started

因此,Completed 前面总是有 6、7 或 8 个 Started 打印输出。