Java线程循环通知()和等待()

时间:2014-11-16 11:34:16

标签: java multithreading monitor

我在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.但是在通知B的时候,A仍有可能出现问题。到达了wait()代码,B已经调用了A.signal()并导致死锁。

如何正确解决此问题?我想到的解决方案是,当B被通知工作时,我会让B的线程休眠几毫秒,但我不认为这是一个好主意。感谢任何帮助,提前谢谢。

3 个答案:

答案 0 :(得分:1)

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

使用wait()时,应该检查状态更改。

在实际代码中,您只能在等待某事时等待。

注意:wait()可以虚假唤醒,并不意味着调用了notify()。正如您所注意到的,如果没有等待(),则notify()不执行任何操作。


您可以使用BlockingQueue在线程之间传递工作/消息,而不是使用此模式。这有wait / notify和包含内置工作的对象。

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

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

答案 1 :(得分:1)

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

答案 2 :(得分:0)

正如您在the 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;
            }
        }
    }
}