简体   繁体   English

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

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

I'm having a code in Java where two objects wait and notify each other when one finished processing. 我在Java中有一个代码,其中两个对象等待并在一个处理完成时互相通知。 I'll keep my code simple with the following example and assuming there are no syntax error (I just want you to know the logic is more important here rather than the syntax). 在下面的示例中,并假设没有语法错误,我将简化代码(我只是想让您知道此处的逻辑比语法更重要)。

Assuming I have object A which is a thread having this pseudo code 假设我有对象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 
        }
    }
}

Then we have here B which is also a thread having this pseudo code 然后我们在这里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
        }
    }
}

So as you can see there's a cycle. 如您所见,这是一个周期。 The problem is I am having a dead-lock and the reason here is because when A is finished processing, it signals B to work before it waits.. But by the time B is notified, there are chances that A still haven't reached the wait() code and B is already calling A.signal() and leads to a dead lock. 问题是我遇到了死锁,这是因为当A完成处理后,它会在等待之前通知B进行工作。但是到通知B时,仍有可能A尚未到达代码中的wait()和B已经在调用A.signal()并导致死锁。

How do I properly solve this problem? 如何正确解决此问题? The solution I have in mind is that when B is notified to work, I will let the thread of B sleep for a number of milliseconds but I don't think this is ever a good idea. 我想到的解决方案是,当通知B工作时,我将让B的线程休眠数毫秒,但我认为这不是一个好主意。 Any help is appreciated, thanks in advance. 任何帮助表示赞赏,在此先感谢。

When you use notify() this should be associated with a state change. 当您使用notify()时,这应与状态更改关联。

When you use wait() this should be associated with a check for a state change. 使用wait()时,应将其与状态更改检查相关联。

In real code, you should only wait when you are waiting for something. 在实际代码中,您仅应在等待某些内容时等待。

Note: wait() can wake spuriously, it doesn't mean notify() was called. 注意:wait()可能会虚假唤醒,这并不意味着调用notify()。 As you noticed, notify() does nothing if nothing is wait()ing. 如您所见,如果什么都没有等待,则notify()不会执行任何操作。


Instead of using this pattern, you can use a BlockingQueue to pass work/messages between threads. 您可以使用BlockingQueue在线程之间传递工作/消息,而不是使用此模式。 This has the wait/notify and the object containing work built in. 这具有等待/通知和内置工作的对象。

However, since you normally need a thread to do the work, there is an ExecutorService builtin to do this. 但是,由于通常需要一个线程来完成工作,因此内置了ExecutorService。 This allows you to pass work to a pool of threads and collect the results. 这使您可以将工作传递给线程池并收集结果。

In short, you should be using an ExecutorService. 简而言之,您应该使用ExecutorService。

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

As you can find described in the Javadoc , you need to put your wait calls inside a loop that checks for a condition. Javadoc所述 ,您需要将wait调用放入检查条件的循环中。 Otherwise, if you don't have a condition variable or expression that you can check, it is possible that you miss the notify because you were not waiting at that point. 否则,如果没有可检查的条件变量或表达式,则可能由于未在此等待而错过了通知。

Also, as others have pointed out, you need to hold the monitor of the object you are calling the wait or notify method on; 另外,正如其他人指出的那样,您需要保留正在调用waitnotify方法的对象的监视器; that's what the synchronized keyword is for. 这就是synchronized关键字的作用。

In the below fix, the condition is very simple; 在下面的修复中,条件非常简单; it's a variable called notified in classes A and B. 这是一个在类A和B中称为notified的变量。

Also, to get this right, A and B need to know about each other. 另外,为正确起见,A和B需要彼此了解。 In your code you seemed to be invoking static methods; 在您的代码中,您似乎正在调用静态方法。 but the notify method needs to be called on an instance, so you need to keep references to the instances of A and B in B and A, respectively. 但是notify方法需要在实例上调用,因此您需要在B和A中分别保留对A和B实例的引用。

This fixes the problems: 这样可以解决问题:

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