CountDownLatch Синхронизация - PullRequest
1 голос
/ 24 марта 2012

У меня есть метод getNewA (), который должен блокироваться, пока какой-нибудь другой поток не вызовет setA (x).Правильно ли использовать CountDownLatch?Я заметил, что существует гонка данных, в которой есть вероятность, что после того, как gate.await () разблокирует другой поток, вызовет setA (x), используя старую защелку, поэтому может быть возможно пропустить значение.Я думал о синхронизации getNewA (), но не приведет ли это к тупику?Любые предложения о том, как подойти к этому?

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

Ответы [ 3 ]

2 голосов
/ 24 марта 2012

Используйте Phaser .Вы можете использовать его так же, как вы хотите здесь, без необходимости создавать новый экземпляр вашего барьера.

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.

1 голос
/ 24 марта 2012

Альтернативой является самостоятельная обработка синхронизации. Я думаю, что вы хотите, чтобы 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();
        }
    }
}

Редактировать: условия гонки возможны, как упоминал Том Андерсон. Спасибо

0 голосов
/ 24 марта 2012

Вы можете использовать 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 в следующий раз, что может быть не так, как вы хотите, так как они оба получат одинаковую ссылку на this.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...