计数器更改时通知线程

Scr*_*ers 6 java concurrency multithreading

我正在尝试为自己设计一个类作为Code Kata,它具有可以设置的value属性,并且该类可以发出ValueListener实例.我们的想法是有一个ValueHolder实例,其中许多客户端线程同时访问它.每个客户端线程都请求了ValueWatcher并调用了waitForValue().

我真正在努力的是我应该在wait()周围的while循环中使用什么条件来避免虚假通知(即值没有改变).我可以看到,这种设计可能使ValueWatcher实例错过更新,但在此阶段我不那么担心.

非常感谢任何提供的指导!

public class ValueHolder {

  private int value = 0;
  private final Object monitor = new Object();

  public void setValue(int value) {
    synchronized(monitor) {
      this.value = value;
      monitor.notifyAll();
    }
  }

  ValueWatcher createChangeWatcher() {
    return new ValueWatcher();
  }

  private class ValueWatcher {
    public int waitForValue() {
      synchronized(monitor) {
        while (==== ??? =====) {
          monitor.wait();
          return value;
        }
      }
    }
  }     
}
Run Code Online (Sandbox Code Playgroud)

Gra*_*ray 3

有趣的问题。这是我想到的一个解决方案。具有版本号以及正在更改的值。每当更新该值时,版本号也会增加,因此对象ValueWatcher可以检查版本是否上升,这意味着发生了更改。

编辑: 我最初有一个AtomicLong,但我从@John Vint 那里窃取了包装对象的想法。

private final VersionValue versionValue = new VersionValue();

public void setValue(int value) {
    synchronized (monitor) {
       versionValue.value = value;
       versionValue.version++;
       monitor.notifyAll();
    }
}

 private class ValueWatcher {
     private long localVersion = 0;
     public int waitForValue() {
         synchronized (monitor) {
             while (true) {
                 if (localVersion < versionValue.version) {
                     // NOTE: the value might have been set twice here
                     localVersion = versionValue.version;
                     return versionValue.value;
                 }
                 monitor.wait();
             }
         }
     }
}

private static class VersionValue {
    int value;
    long version;
}
Run Code Online (Sandbox Code Playgroud)

此外,尽管可能出现虚假唤醒,但请务必记住以下内容:

始终在循环内调用 wait 来测试正在等待的条件。不要假设中断是针对您正在等待的特定条件的,或者条件仍然为真。

更多的是关于竞争条件和生产者/消费者模型,而不是虚假唤醒。请参阅我的页面,了解相关内容