gpt4 book ai didi

multithreading - IllegalMonitorStateException调用wait()和notify()

转载 作者:行者123 更新时间:2023-12-03 13:17:29 26 4
gpt4 key购买 nike

我已经阅读了生产者和消费者的示例,并且做了一些改动。 Pro()将打印“第一”,而con()将打印“第二”。我希望每个“第二”出现在“第一”之后。

public class test {
test() { }

synchronized void pro() {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
System.out.println("First!");
notify();
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}

synchronized void con() {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Second!");
notify();
}
}
}).start();
}

public static void main(String[] args) {
test m = new test();
m.pro();
m.con();
}
}

发生的错误是:
First!
Exception in thread "Thread-0" Exception in thread "Thread-1"
java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at test$1.run(test.java:12)
at java.lang.Thread.run(Unknown Source)
java.lang.IllegalMonitorStateException
at java.lang.Object.wait(Native Method)
at java.lang.Object.wait(Object.java:503)
at test$2.run(test.java:32)
at java.lang.Thread.run(Unknown Source)

最佳答案

这里同时发生了几个问题。

首先是显而易见的IllegalMonitorStateException。当调用线程不持有对象的监视器锁定时,在对象上调用waitnotify时,将发生此异常。即使调用在语法上在synchronized方法内发生,但对waitnotify的实际调用在不同的线程上发生并且在不同的对象上运行。

发生的事情是您的procon方法在实例上同步。由于它们是通过main方法调用的,因此主线程是获取监视器锁的线程。但是这些方法只是启动其他线程,然后释放锁。
waitnotify调用是隐式的this.waitthis.notify,它们在Runnable匿名内部类之内,因此,在这些情况下,this引用的是Runnable实例,而不是已同步的外部test实例。规则是,在对象上调用wait(或notify)的同一线程也必须在该对象上拥有监视器锁定。由于不是这种情况,因此会抛出IllegalMonitorStateException。另一个问题是waitnotify调用位于不同的 Runnable实例上。不同的线程必须在同一对象上使用wait/notify进行通信。

您需要做的是重新排列代码,以便synchronized块出现在执行实际同步的线程中。然后,您要确保synchronizedwaitnotify操作都在同一对象上。也许最好的方法是将test实例存储在静态字段中(例如,使m为静态字段而不是局部变量)。 run方法是Runnable实例的成员,因此您不能仅使这些方法同步。相反,您必须使用synchronized块并传递要在其上进行同步的实例。您也可以从synchronizedpro方法中删除con关键字,因为这些方法实际上不需要同步。结果代码如下所示:

static test m = new test();

void pro() {
new Thread(new Runnable() {
@Override
public void run() {
synchronized (m) {
...
m.notify();
...
m.wait();
...
}
}
}).start();
}

您必须执行类似于 con方法的操作。

现在,代码应该在不抛出 IllegalMonitorStateException的情况下运行。但这揭示了第二个问题:它可能不起作用。由于丢失的唤醒问题,它可能会死锁。完整的解释超出了此答案的范围。简要地说,如果首先运行由 pro启动的线程,则在没有线程等待时,它可能会调用 notify。如果发生这种情况,则什么也不会发生。然后,该线程继续并调用 wait。接下来, con线程可能会启动,并且它首先要做的是调用 wait。现在,两个线程都被阻止在 wait中,并且永远不会出现 notify

解决此问题的方法是根据对象的状态设置等待和通知 。在不检查对象状态的情况下调用wait无效,在不更改对象状态的情况下调用notify也无效。

有关如何正确使用waitnotify的完整说明,请参阅Goetz,《 Java并发实践》第14章。

关于multithreading - IllegalMonitorStateException调用wait()和notify(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23976599/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com