简体   繁体   English

CountDownLatch同步

[英]CountDownLatch Synchronization

I have a method getNewA() that is supposed to block until some other thread calls setA(x). 我有一个方法getNewA(),它应该阻塞,直到其他一些线程调用setA(x)。 Is it correct to use a CountDownLatch? 使用CountDownLatch是否正确? I noticed that there is a data race in that there is a possibility that after gate.await() unblocks another thread will call setA(x) using the old latch, therefore it might be possible to miss a value. 我注意到有一个数据竞争,有可能在gate.await()取消阻塞后,另一个线程将使用旧锁存器调用setA(x),因此可能会错过一个值。 I thought about synchronizing getNewA() but wouldn't that result in a deadlock? 我想同步getNewA()但不会导致死锁吗? Any suggestions on how to approach this? 有关如何处理此问题的任何建议?

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

Use a Phaser . 使用Phaser You can reuse it just like you want here without having to create a new instance of the your barrier. 您可以像在此处一样重复使用它,而无需创建障碍的新实例。

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();
    }
}

Each time setA is called it will increment to a new phase and the phaser.awaitAdvance(phaser.getPhase()) will return out. 每次调用setA ,它都会增加到一个新阶段, phaser.awaitAdvance(phaser.getPhase())将返回。 At this point the new phase will equal the phaser.getPhase()+1 此时,新阶段将等于phaser.getPhase()+1

Note: this requires Java 7. 注意:这需要Java 7。

An alternative is to handle synchronization yourself. 另一种方法是自己处理同步。 What I think you want is for the getA to return a value that is set after a thread currently enters. 我认为你想要的是让getA返回一个当前进入线程后设置的值。 You can use this as the wait() criteria. 您可以将其用作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();
        }
    }
}

Edit: Race condition is possible as TomAnderson mentioned. 编辑:汤姆安德森提到的竞争条件是可能的。 Thanks 谢谢

You could use a Semahore : 你可以使用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();
    }
}

If the semaphore has 0 permits left and two threads call getA one after the other, both will block and only of them will be non-deterministically chosen to wake up when setA is called. 如果信号量剩下0个许可,两个线程一个getA一个地调用getA ,则两个线程都将阻塞,并且只有在调用getAsetA确定地选择它们才能唤醒。

If setA is called twice in a sequence, it will allow two threads to call getA next time, which may not be what you want, since both of them will get the same reference to this . 如果setA是序列叫了两声,这将允许两个线程调用getA下一次,你想要的东西可能不是,因为他们都将获得相同的参照this

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM