等待Java活动 – 有多难?

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

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

现在这看起来很好,除非线程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... ... } 

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

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

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

题:

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

如何手动完成:

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

 synchronized(foo) { while(!condition) { foo.wait(); } } 

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

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

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

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

例如

 boolean ready = false; // thread 1 synchronized(lock) { ready = true; lock.notifyAll(); } // thread 2 synchronized(lock) { while(!ready) lock.wait(); } 

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

如果您在不设置值或检查值的情况下使用notify或wait,某些编码分析工具会发出警告。

你可以使用wait()和超时,在这种情况下你不会冒险等待。 另请注意,即使根本没有notify(),wait()也可能返回,因此,您需要将等待包装在一些条件循环中。 这是在Java中等待的标准方式。

 synchronized(syncObject) { while(condition.isTrue()) { syncObject.wait(WAIT_TIMEOUT); } } 

(在你的主题2中)

编辑:在循环外同步移动。

最简单的方法就是说

firstThread.join();

这将阻塞,直到第一个线程终止。

但您可以使用wait / notify实现相同的function。 不幸的是你还没有发布你真正的代码片段,但我想如果你在调用notify时没有退出等待,因为你没有把它们都放到synchronized块中。 请注意,对于等待/通知对, synchronized块的“参数”必须相同。

我在两个线程之间使用了BlockingQueue 。 5分钟前使用waitnotify是如此;)

 enum Event { Event, Stop; } BlockingQueue queue = new LinkedBlockingQueue(); // Thread 1 try { while(true) { ...do something... queue.put(Event.Event); ...wait for some condition that might never happen... ... } } finally { // Tell other thread we've finished. queue.put(Event.Stop}; } // Thread 2 ... switch ( queue.take() ) { case Event: ... break; default: ... break; }