Java:CountDownLatch是否线程安全

9
CountDownLatch文档中,我看到了以下内容:

public void run() {
      try {
        startSignal.await();
        doWork();
        doneSignal.countDown();
      } catch (InterruptedException ex) {} // return;
}

这里的 startSignaldoneSignalCountDownLatch 对象。

文档没有提到该类是否线程安全。


1
在这种情况下,定义“线程安全”。 - OldCurmudgeon
线程安全,在这种情况下,例如要确保只有一个线程在同一时间调用 countDown 方法。方法签名并没有说明它是同步的:public void countDown() - treecoder
CountDownLatch 保证了 await 方法会阻塞,直到 countDown() 方法被调用了指定的次数,无论有多少个线程同时调用它。 - Misha
2个回答

7
由于它被设计为由多个线程使用,因此可以合理地假设它对大多数“线程安全”的含义是“线程安全”的。
甚至有一个“happens-before”承诺(来自您的链接:https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CountDownLatch.html):

内存一致性效果:在计数达到零之前,调用countDown()之前线程中的操作会先行发生于在另一个线程中相应await()成功返回之后的操作。

关于您特定问题的参考:“如果两个线程同时调用countDown会怎样?它不会只执行一次计数动作吗?” 不会,每次都会执行两个countDown。

但是调用 countDown 本身不应该同步吗?如果两个线程同时调用 countDown,那么它不仅会有效地执行一次倒计时操作吗? - treecoder
3
@treecoder,你似乎把“一个方法是线程安全的”和“一个方法被同步化了”等同起来了。这是不正确的。有几种方法可以使一个方法在不同线程中是安全的,而不必将其同步化。CountDownLatch 内部使用非阻塞的、线程安全的操作。Java.util.concurrent 中的所有内容都是设计用于多个线程的。 - JB Nizet

0

是的,类或者更确切地说,在CountDownLatch对象上调用的方法是线程安全的。

为了使这些操作,如countDown()await()线程安全,它们没有使用synchronize块或函数。相反,它们使用了比较和交换策略。 下面是证明这一点的源代码:

sync.releaseShared(1);

public final boolean releaseShared(int arg) {
    if (tryReleaseShared(arg)) {
        doReleaseShared();
        return true;
    }
    return false;
}

protected boolean tryReleaseShared(int releases) {
        // Decrement count; signal when transition to zero
        for (;;) {
            int c = getState();
            if (c == 0)
                return false;
            int nextc = c-1;
            if (compareAndSetState(c, nextc))
                return nextc == 0;
        }
    }

以上代码是总体实现的一部分,您可以查看其他方法(如await())的源代码。

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