Java 倒计时锁存和进一步同步

Java 倒计时锁存和进一步同步,java,multithreading,synchronization,countdownlatch,Java,Multithreading,Synchronization,Countdownlatch,假设我有以下类定义,当一个线程想要为多个(可能)等待线程设置一个类时: public class A {     private int a;     private CountDownLatch gate;     public A(int a) {         a = 1;         gate = new CountDownLatch(1);     }     public int getA() {         latch.await();         return

假设我有以下类定义,当一个线程想要为多个(可能)等待线程设置一个类时:

public class A {
    private int a;
    private CountDownLatch gate;

    public A(int a) {
        a = 1;
        gate = new CountDownLatch(1);
    }

    public int getA() {
        latch.await();
        return a;
    }

    public void setA(int a) {
        this.a = a;
        gate.countDown();
    }
}
在我看来,a需要是易失性的,但我不确定……有人能告诉我为什么,如果有的话,getA需要额外的同步,或者a需要是易失性的吗?

根据:

在计数达到零之前,调用
countDown()
之前线程中的操作发生在另一个线程中相应的
wait()
成功返回后的操作之前

因此,如果只调用
setA
一次,就不需要额外的同步。如果您再次调用它,因为计数已经是0,您将无法获得相同的保证

如果预期用途是只调用
setA
一次,那么如果多次调用该异常以强制执行该契约,则可以抛出异常(尽管在没有额外同步的情况下,检查计数并将新值分配给原子可能很棘手)


如果您很高兴可以多次调用
setA
,那么您需要额外的同步。

实际上
a
不需要易变,因为
倒计时()
加载并存储到
AbstractQueuedSynchronizer
的volatile
状态
变量中,该变量在
倒计时闩锁
中使用。易失性存储触发内存屏障()。根据JMM,所有以前的存储(对于其他变量)对于其他线程都是可见的

assylias是正确的,只有调用
setA()
一次才是正确的,因为您将闩锁构造为
新的倒计时闩锁(1)

非常感谢!如何实现这种内存一致性?在我看来,闩锁与类A没有任何关系,无法跨多个线程同步A的状态…
如何实现内存一致性?
我在回答中描述了这一点:)@Bober02所有读取线程(调用
getA
)将在
等待
完成后读取
A
(程序顺序)。写入线程(调用
setA
的唯一线程)在写入
a
(程序顺序)后正在调用
countDown
。因为发生在关系可传递之前,javadoc中给出的保证意味着对
a
的写入发生在对
a
的读取之前。所有这些都假设
setA
只调用一次。同意,但这仍然是高级别的。易失性写入/障碍更让我失望alley@Bober02我不知道你花了多少钱ct—在这种情况下,处理关系发生在关系之前就足够了。您可以参考处理器屏障指令,但它们不是Java内存模型的一部分(即使JVM通常使用它们来实现JMM).啊,所以在闩锁的状态中存在易失性读/写。这反过来又是一个完整的屏障,因此更改会在缓存等之间传播。正确吗?是的,确实会发生这种情况。