Java 倒计时锁存同步
我有一个getNewA()方法,该方法应该一直阻塞,直到其他线程调用setA(x)。使用倒计时锁存器正确吗?我注意到有一种数据竞争,在gate.await()解除阻塞后,另一个线程可能会使用旧锁存器调用setA(x),因此可能会丢失一个值。我考虑过同步getNewA(),但这不会导致死锁吗?关于如何处理这个问题有什么建议吗Java 倒计时锁存同步,java,multithreading,concurrency,Java,Multithreading,Concurrency,我有一个getNewA()方法,该方法应该一直阻塞,直到其他线程调用setA(x)。使用倒计时锁存器正确吗?我注意到有一种数据竞争,在gate.await()解除阻塞后,另一个线程可能会使用旧锁存器调用setA(x),因此可能会丢失一个值。我考虑过同步getNewA(),但这不会导致死锁吗?关于如何处理这个问题有什么建议吗 package test; import java.util.concurrent.CountDownLatch; public class A { priva
package test;
import java.util.concurrent.CountDownLatch;
public class A {
private int a;
private CountDownLatch gate;
public A(int a) {
a = 1;
gate = new CountDownLatch(1);
}
A getNewA() throws InterruptedException { // wait for new a...
gate.await();
gate = new CountDownLatch(1);
return this;
}
public synchronized int getA() {
return a;
}
public synchronized void setA(int a) {
gate.countDown();
this.a = a;
}
}
使用一个。您可以像在这里一样重用它,而无需创建屏障的新实例
public class A {
private int a
private final Phaser phaser = new Phaser(1);
public A(int a) {
a = 1;
}
A getNewA() throws InterruptedException { // wait for new a...
phaser.awaitAdvance(phaser.getPhase());
return this;
}
public synchronized int getA() {
return percent;
}
public synchronized void setA(int a) {
this.a = a
phaser.arrive();
}
}
每次调用setA
时,它都会增加到一个新的阶段,phaser.awaitAdvance(phaser.getPhase())
将返回。此时,新相位将等于phaser.getPhase()+1
注意:这需要Java 7。您可以使用
Semahore
:
package test;
import java.util.concurrent.Semaphore;
public class A {
private int a
private Semaphore semaphore = new Semaphore(0);
public A(int a) {
a = 1;
}
A getNewA() throws InterruptedException { // wait for new a...
semaphore.acquire();
return this;
}
public synchronized int getA() {
return percent;
}
public synchronized void setA(int a) {
this.a = a;
semaphore.release();
}
}
如果信号量剩下0个许可,并且两个线程依次调用getA
,则两个线程都将阻塞,并且只有其中一个线程在调用setA
时被非确定性地选择唤醒
如果在一个序列中调用两次
setA
,它将允许两个线程下次调用getA
,这可能不是您想要的,因为它们都将获得对的相同引用,这另一种方法是自己处理同步。我认为您需要的是getA
返回一个在线程当前进入后设置的值。您可以将其用作wait()
标准
public class A {
private int a;
private long updateCount = 0;
private final Object lock = new Object();
public A getNewA() throws InterruptedException { // wait for new a...
synchronized(lock) {
long currentCount = updateCount ;
while (currentCount == updateCont) {//assumes never decrementing
lock.wait();
}
return this;
}
}
public int getA() {
synchronized(lock) {
return a;
}
}
public void setA(int a) {
synchronized(lock) {
this.a = a;
updateCount++;
lock.notifyAll();
}
}
}
编辑:如Anderson所述,竞争条件是可能的。谢谢如果另一个线程在getNewA()
之前调用setA
,那意味着什么?如果setA在getNewA()之前,那么信号量对您更有用吗。调用getNewA()的线程将返回实例而不阻塞,如果在调用getNewA()
之前调用了两次setA()
,那么会发生什么?对getNewA()
的两个调用可以不阻塞地通过吗?如果两个线程都在等待getNewA()
,并且有一个setA()
调用传入,那么这两个线程都应该被解锁还是只有一个?您确实需要仔细描述您的情况:)是否应该getNewA
真的返回A,而不是int?当前代码有一个争用条件:如果两个线程调用getNewA()
并阻塞,那么另一个线程将其唤醒,然后第四个线程立即调用getNewA()
,第四个线程可能会看到一个值gate
,该值由第一个线程设置为离开gate,但在任何setA()
调用线程有机会看到它之前,该值会被第二个线程覆盖以离开gate。这个可怜的第四个线程将永远不会被解锁。如果我使用java 6,还有其他选择吗?@xxtommoxx我想到了FutureTask的一些用法,但不太喜欢它来发布它。我也许能做得更好。@lhballoti不幸的是不能。SynchronousQueue要求放置线程等待,直到有一个拉动线程。这一要求要求线程只发送信号并继续工作。如果没有线程在等待信号,那也没关系。@JohnVint事实上,我没有想到Puting线程会阻塞。如果在同一毫秒内得到多个更新,那么使用这样的时间戳很容易受到竞争条件的影响,而毫秒在计算中是很长的时间。你最好使用计数器而不是时间戳;所有访问都受锁上的同步保护。可以将其视为一种不同寻常的成对编程@都铎不一定。正如您在回答中提到的,信号量不会通知所有线程唤醒。