倒计时和进一步同步
Countdownlatch and further synchronisation
假设我有以下 class 定义,当一个线程想要为多个(可能)等待的线程设置 a 时:
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 需要可变?
根据the javadoc:
Until the count reaches zero, actions in a thread prior to calling countDown()
happen-before actions following a successful return from a corresponding await()
in another thread.
因此,如果您只调用 setA
一次,则不需要额外的同步。如果你第二次调用它,因为计数已经为 0,你将不会得到相同的保证。
如果预期的用途是只调用 setA
一次,如果多次调用它来执行该合同,您可能会抛出异常(尽管检查计数并为原子分配新值可能是没有额外的同步就很棘手)。
如果您对 setA
可以被多次调用感到高兴,那么您需要额外的同步。
实际上a
不需要是volatile的,因为countDown()
加载并存储到AbstractQueuedSynchronizer
的volatilestate
变量中,在CountDownLatch
中使用.易失性存储触发 memory-barrier (great in-depth article about Memory Barriers and etc in JSR-133)。根据 JMM,所有以前的存储(对其他变量)将对其他线程可见。
assylias 是对的,只有调用一次 setA()
才会正确,因为你将 latch 构造为 new CountDownLatch(1)
.
假设我有以下 class 定义,当一个线程想要为多个(可能)等待的线程设置 a 时:
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 需要可变?
根据the javadoc:
Until the count reaches zero, actions in a thread prior to calling
countDown()
happen-before actions following a successful return from a correspondingawait()
in another thread.
因此,如果您只调用 setA
一次,则不需要额外的同步。如果你第二次调用它,因为计数已经为 0,你将不会得到相同的保证。
如果预期的用途是只调用 setA
一次,如果多次调用它来执行该合同,您可能会抛出异常(尽管检查计数并为原子分配新值可能是没有额外的同步就很棘手)。
如果您对 setA
可以被多次调用感到高兴,那么您需要额外的同步。
实际上a
不需要是volatile的,因为countDown()
加载并存储到AbstractQueuedSynchronizer
的volatilestate
变量中,在CountDownLatch
中使用.易失性存储触发 memory-barrier (great in-depth article about Memory Barriers and etc in JSR-133)。根据 JMM,所有以前的存储(对其他变量)将对其他线程可见。
assylias 是对的,只有调用一次 setA()
才会正确,因为你将 latch 构造为 new CountDownLatch(1)
.