等待Java活动 - 有多难?

Kos*_*sta 16 java events multithreading

我有一个线程,不时更新它的状态,我希望第二个线程能够等待第一个线程完成.像这样的东西:

Thread 1:
    while(true) {
        ...do something...
        foo.notifyAll()
        ...wait for some condition that might never happen...
        ...
    }

Thread 2:
    ...
    foo.wait();
    ...
Run Code Online (Sandbox Code Playgroud)

现在这看起来不错,除非线程1的notifyAll()在线程2的wait()之前运行,在这种情况下,线程2等待直到线程1 再次通知(这可能永远不会发生).

我的解决方案:

a)我可以使用CountDownLatch或Future,但两者都存在问题,即它们本身只运行一次.也就是说,在Thread 1的while循环中,我需要创建一个新的foo来等待每次,而Thread 2需要询问哪个foo等待.我对简单的写作感觉不好

while(true) {
   foo = new FutureTask(); 
   ...
   foo.set(...);
   ...wait for a condition that might never be set...
   ...
}
Run Code Online (Sandbox Code Playgroud)

因为我担心在foo = new FutureTask()时,当有人等待旧的foo时会发生什么(因为"某种原因",set没有被调用,例如异常处理中的错误)?

b)或者我可以使用信号量:

class Event {
   Semaphore sem;
   Event() { sem = new Semaphore(1); sem . }
   void signal() { sem.release(); }
   void reset() { sem.acquire(1); }
   void wait() { if (sem.tryAcquire(1)) { sem.release(); } }
}
Run Code Online (Sandbox Code Playgroud)

但我担心有一些竞争条件,如果有多个线程正在等待(),而另一个信号()s和reset()s.

题:

Java API中没有类似于Windows事件行为的内容吗?或者,如果你鄙视Windows,就像golang的WaitGroup(即允许countUp()的CountDownLatch)?什么?

如何手动完成:

线程2不能简单地等待因为虚假唤醒而在Java中无法知道Object.wait()返回的原因.所以我需要一个条件变量来存储事件是否发出信号.线程2:

synchronized(foo) {
    while(!condition) {
        foo.wait();
    }
}
Run Code Online (Sandbox Code Playgroud)

并且线程1当然在同步块中将条件设置为true.感谢周末提示!

是否存在包含该行为的现有类?

或者我是否需要复制并粘贴代码?

Pet*_*rey 21

标准做法是在执行notifyAll时更改某些状态,并在执行wait()时检查某些状态.

例如

boolean ready = false;

// thread 1
synchronized(lock) {
    ready = true;
    lock.notifyAll();
}


// thread 2
synchronized(lock) {
    while(!ready) 
        lock.wait();
}
Run Code Online (Sandbox Code Playgroud)

通过这种方法,线程1或线程2是否首先获得锁定并不重要.

如果您在不设置值或检查值的情况下使用通知或等待,某些编码分析工具会向您发出警告.

  • `lock.wait()`释放`lock`并在返回之前重新获取它. (5认同)
  • 这不会导致死锁情况,其中线程2抓住`lock`并且在它离开块之前不会释放(但它不会离开,因为它正在等待'ready`为真,这将永远不会发生线程2持有"锁定")? (4认同)
  • @AshleyFrieze一个简单的`if`在所有情况下都不够.我上周修复了一个并发错误,其中没有使用循环,并且`wait()`在虚假地醒来,因为它可以记录它. (4认同)
  • @AshleyFrieze问题是`wait()`将在99.99%的时间内正常工作,但在负载下我们已经看到这0.01%导致一小部分测试以一种难以重现的方式随机失败.自添加循环以来,经过一周的测试后问题仍未重新出现. (2认同)