java - 当在同步块(synchronized block)中使用wait()方法时,JVM在等待notify()时会释放监视器吗?

标签 java multithreading event-handling

我有一个线程启动另一个线程,该线程执行一个操作,该操作将导致事件在运行后触发。我需要在第一个线程中捕获该事件(通过事件监听器)并继续其余的工作。我的问题是,当第一个线程等待事件监听器调用 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
}

因此,您还需要一些东西来指示“已执行”条件 - 最简单的方法是创建一个名为 performedboolean 字段,并将其设置为在 onPerformed 方法中调用 notify 之前,true

thread1 将正确地看到此标志的值,因为 thread2thread1 获取同一监视器之前释放监视器,并且这建立了Java 内存模型规范中描述的先发生关系。

关于java - 当在同步块(synchronized block)中使用wait()方法时,JVM在等待notify()时会释放监视器吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25588782/

相关文章:

java - 如何在android中的onResponse方法之外访问响应值

java - 我是否需要使用 volatile,如果 2 个不同的写入和读取线程永远不会同时存在

c# - WPF Canvas VisibilityChanged 事件

c - 如何合并来自不同项目的事件循环

java - try and catch 语句没有给我结果?

java - 无法在hadoop中执行程序

java - 数组输入未相加。 -- 总计 += ScoreArray[i];

C++14 shared_timed_mutex VS C++11 互斥量

multithreading - OpenMP 可以用于 GPU 吗?

asp.net - 用户控件事件不会在 Httphandler 中触发