Java 中的 CountDownLatch 需要额外同步吗?

CountDownLatch in Java need additional synchronization?

假设我有以下代码:

public class CountDownLatchExample {  // Note : Exception handling ommited
    void main(){
        CountDownLatch startSignal = new CountDownLatch(1);
        CountDownLatch doneSignal = new CountDownLatch(N_PARTIES);
        for(int i = 0; i < N_PARTIES; i++){ // create and start threads
            new Thread(() -> {
                startSignal.await();    // Wait startSignal before doing Work
                doWork();
                doneSignal.countDown();
            }).start();
        }
        // (...) do something else              // Don't let run yet
        startSignal.countDown();                // Let all threads proceed
        // (...) do something else
        doneSignal.await();                     // Wait for all threads to finish
    }
}

main 线程创建并启动工作线程。在run方法中,其他线程等待main线程调用startSignal.countDown(),然后就可以调用doWork()和doneSignal.countDown().

我知道线程调用的 countDown() 和来自 await 的 return 线程之间存在先行关系,那么如果线程调用 doneSignal.countDown(), 它所做的对所有其他线程都是可见的。

但是我的问题是run()方法是否顺序执行,是否需要加同步??

因为在调用startSignal.countDown()时,所有线程都可以执行run方法,但是假设在doWork()方法中有一些共享变量发生变化,或者也只是并发执行 run(),可能有三个线程同时执行 doWork(),然后其中两个线程在 doneSignal.countDown() 之前调度,第三个线程调用 doneSignal.countDown()。如果其他两个线程已经执行了 doWork() 并且它们只需要调用 doneSignal.countDown(),那么 happens-before 关系在这里有点无用,因为它们没有看到第三个线程做了什么,因为它们“一起”执行 doWork()。

CountDownLatch不保证mutual exclusion of the accesses to the share data, rather this mechanism is used to synchronized -- in the sense of one waiting for the other -- parallel task among each other. Similar to the functionality provided by a Cyclic barrier。实际上,正如您所描述的,这就是您在代码中使用此机制的原因;协调 main 和其余线程的执行。

如果 doWork() 方法包含线程之间的共享状态,并发修改,那么您可能有 race-condition。因此,您需要使用 synchronized 子句确保共享的互斥。