我有一个线程启动另一个线程,该线程执行一个操作,该操作将导致事件在运行后触发。我需要在第一个线程中捕获该事件(通过事件监听器)并继续其余的工作。我的问题是,当第一个线程等待事件监听器调用 notify()
时,它会释放监视器吗?如果不是,我该如何设计这个算法?我是否正确使用了 wait()
和 notify()
方法并获得了正确的锁(thread1)?
代码如下:
public class Thread1 {
public void run() {
Thread thread1 = Thread.currentThread();
EventListener listener = new EventListener(thread1);
Performer performer = new Performer();
performer.addOnPerformedListener(listener);
synchronized(thread1) {
performer.run(); // Launches thread 2
thread1.wait();
}
...
}
public class EventListener implements Performer.OnPerformedListener {
private Thread thread;
public EventListener(Thread thread) {
this.thread = thread;
}
@Override
public void onPerformed() {
synchronized (thread) {
thread.notify();
}
}
}
}
最佳答案
您正在做的事情的基本想法是正确的。正如 Object#wait()
方法的 Javadoc 所指出的,它会在等待时释放您使用 synchronized
语句获取的监视器:
The current thread must own this object's monitor. The thread releases ownership of this monitor and waits until another thread notifies threads waiting on this object's monitor to wake up
但是,有一个原因不能保证它在您实现它时在每种情况下都能正常工作,原因是 wait
调用也可以通过“中断和虚假”唤醒唤醒”。 (正如您当前实现的那样,它在 99% 的情况下都能正常工作,这使得它变得更加棘手,因为这给人一种它总是有效的错误感觉)
正如 Javadoc 所述:
As in the one argument version, interrupts and spurious wakeups are possible, and this method should always be used in a loop:
synchronized (obj) { while (<condition does not hold>) obj.wait(); ... // Perform action appropriate to condition }
因此,您还需要一些东西来指示“已执行”条件 - 最简单的方法是创建一个名为 performed
的 boolean
字段,并将其设置为在 onPerformed
方法中调用 notify
之前,true
。
thread1
将正确地看到此标志的值,因为 thread2
在 thread1
获取同一监视器之前释放监视器,并且这建立了Java 内存模型规范中描述的先发生关系。
关于java - 当在同步块(synchronized block)中使用wait()方法时,JVM在等待notify()时会释放监视器吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25588782/