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

3

假设我有以下代码:

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

主线程创建并启动工作线程。在run方法中,其他线程等待,直到主线程调用startSignal.countDown(), 然后才能调用doWork()doneSignal.countDown()

我知道调用线程的countDown()与从await返回的线程之间存在happens-before关系, 那么如果一个线程调用doneSignal.countDown(),它所做的事情对所有其他线程都是可见的。

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

因为当调用startSignal.countDown()时,所有线程都可以执行run方法,但是假设在doWork()方法中有一些共享变量发生了变化,或者只是同时执行run(),可能会有三个线程同时执行doWork(),然后其中两个在线程调用doneSignal.countDown()之前被调度出去了,第三个线程调用了doneSignal.countDown()。在这种情况下,happens-before关系有点无用,因为其他两个线程已经执行了doWork(),只需要调用doneSignal.countDown(),因为它们没有看到第三个线程所做的事情,因为它们一起执行了doWork()

1个回答

2

CountDownLatch 不能保证对共享数据的访问具有互斥性,而是用于同步并发任务之间的等待,类似于 循环屏障 提供的功能。实际上,正如您所描述的那样,这就是您在代码中使用此机制的原因;以协调 主线程 和其余线程的执行。

如果 doWork() 方法包含在线程之间修改的共享状态,则可能存在竞态条件。因此,您需要使用例如 synchronized 子句确保该共享状态的互斥访问。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接