繁体   English   中英

Java线程循环Notify()和Wait()

[英]Java Threading Cyclic Notify() and Wait()

我在Java中有一个代码,其中两个对象等待并在一个处理完成时互相通知。 在下面的示例中,并假设没有语法错误,我将简化代码(我只是想让您知道此处的逻辑比语法更重要)。

假设我有对象A,它是具有此伪代码的线程

class A is Thread {
    run() {
        while(true) {
            wait(); // wait for signal from B
            // then do something if signal received
            B.signal(); // let B know that we're done and wait again 
        }
    }
}

然后我们在这里B也是一个具有此伪代码的线程

class B is Thread {
    run() {
        while(true) {
            // Do something
            A.signal(); // Let A know to continue processing
            wait(); // Wait for signal from A before doing something again
        }
    }
}

如您所见,这是一个周期。 问题是我遇到了死锁,这是因为当A完成处理后,它会在等待之前通知B进行工作。但是到通知B时,仍有可能A尚未到达代码中的wait()和B已经在调用A.signal()并导致死锁。

如何正确解决此问题? 我想到的解决方案是,当通知B工作时,我将让B的线程休眠数毫秒,但我认为这不是一个好主意。 任何帮助表示赞赏,在此先感谢。

当您使用notify()时,这应与状态更改关联。

使用wait()时,应将其与状态更改检查相关联。

在实际代码中,您仅应在等待某些内容时等待。

注意:wait()可能会虚假唤醒,这并不意味着调用notify()。 如您所见,如果什么都没有等待,则notify()不会执行任何操作。


您可以使用BlockingQueue在线程之间传递工作/消息,而不是使用此模式。 这具有等待/通知和内置工作的对象。

但是,由于通常需要一个线程来完成工作,因此内置了ExecutorService。 这使您可以将工作传递给线程池并收集结果。

简而言之,您应该使用ExecutorService。

如果A使用B的结果,那么您可以考虑使用BlockingQueue

Javadoc所述 ,您需要将wait调用放入检查条件的循环中。 否则,如果没有可检查的条件变量或表达式,则可能由于未在此等待而错过了通知。

另外,正如其他人指出的那样,您需要保留正在调用waitnotify方法的对象的监视器; 这就是synchronized关键字的作用。

在下面的修复中,条件非常简单; 这是一个在类A和B中称为notified的变量。

另外,为正确起见,A和B需要彼此了解。 在您的代码中,您似乎正在调用静态方法。 但是notify方法需要在实例上调用,因此您需要在B和A中分别保留对A和B实例的引用。

这样可以解决问题:

class A is Thread {
    private B b;
    private boolean notified;

    public void run() {
        while(true) {
            synchronized(this) {
                while (!notified) {
                    try {
                        wait(); // wait for signal from B
                    } catch (InterruptedException e) {}
                }
                notified = false;
            }
            synchronized(b) {
                // then do something if signal received
                b.notified = true;
                b.notify(); // let B know that we're done and wait again 
            }
        }
    }
}

class B is Thread {
    private A a;
    private boolean notified;
    public void run() {
        while(true) {
            synchronized(a) {
                // Do something
                a.notified = true;
                a.notify(); // Let A know to continue processing
            }
            synchronized(this) {
                while (!notified) {
                    try {
                        wait(); // Wait for signal from A before doing something again
                    } catch (InterruptedException e) {}
                }
                notified = false;
            }
        }
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM