gpt4 book ai didi

Java wait() 不会被 notify() 唤醒

转载 作者:行者123 更新时间:2023-12-01 18:30:01 29 4
gpt4 key购买 nike

你好,我已经调试了我的代码一整天,但我就是看不出哪里可能出错。

我在主线程上使用 SerialPortEventListener,在工作线程中我有一个与服务器通信的客户端套接字。由于此工作线程到达return之后,我仍然需要在主线程中完成一些总结工作,我想创建一个“伪线程”,它在主线程中等待,直到从监听器通知它onEvent 方法。

但是这个伪线程似乎永远在等待。

我检查了锁定的线程pseudoThread,它们在Runnable和Listener类中应该具有相同的对象ID。

显示“PseudoThread waiting”,但从未显示 PseudoThread awake。

Console output shows: PseudoThread waiting .. .. false notified pseudothread.

PS 如果我使用 public final Object lock = new Object(); 在 Main 类中创建一个锁,并将所有 main.pseudoThread 替换为 main.lock,我得到 java.lang.IllegalMonitorStateException。

private class Pseudo implements Runnable{
Main main;
public Pseudo(Main main) {
this.main = main;
}

@Override
public void run() {
synchronized(main.pseudoThread){
try {
System.out.println("PseudoThread waiting");
main.pseudoThread.wait();
System.out.println("PseudoThread awake");
} catch (InterruptedException e) {
e.printStackTrace();
return;
}
}

}

}

在主方法中:

public static void main(String[] args) {
Main main = new Main();
main.initArduino();
//more code. including starting the working thread
main.pseudoThread = new Thread(main.new Pseudo(main));
main.pseudoThread.start();
try {
main.pseudoThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void initArduino() {
arduino = new Arduino(this);
if(!arduino.initialize())
System.exit(1);
}

以及监听器类(也在主线程中运行)

//class constructor;
public Arduino(Main Main){
this.main = Main;
}
//listening method
public void serialEvent(SerialPortEvent oEvent){
//some code to interract with working thread.
record();

}
private void record(){
synchronized(main.pseudoThread){
main.pseudoThread.notify();
System.out.println("notified pseudothread.");
}
}

最佳答案

在不深入了解实际情况的情况下,我可以看到您对 wait()/notify() 的使用都是错误的。您可能正在遇到“丢失通知”。如果调用notify() 函数时没有线程在等待它,那么它什么都不做。如果你的serialEvent()函数在其他线程调用wait()之前调用notify(),那么通知将会丢失。

考虑这个例子:

class WaitNotify() {
private final Object lock = new Object();
private long head = 0;
private long tail = 0;

public void consumer() {
synchronized (lock) {
while(head == tail) {
lock.wait();
}
doSomething();
count head += 1;
}
}

public void producer() {
synchronized (lock) {
tail += 1;
lock.notify();
}
}
}

要点是:

(1) Consumer() 函数等待数据之间的某种关系变为真:这里,它等待 head != tail .

(2) Consumer() 函数在循环中等待。造成这种情况的原因有两个: (a) 许多程序都有多个消费者线程。如果消费者 A 从 wait() 中醒来,则不能保证消费者 B 尚未声明他们正在等待的任何内容。 (b) Java 语言规范允许 foo.wait() 有时返回,即使 foo.notify() 尚未被调用。这就是所谓的“虚假唤醒”。允许虚假唤醒(只要它们不经常发生)可以更轻松地实现 JVM。

(3) 锁对象与程序用来保护条件所依赖的变量的锁相同。如果此示例是较大程序的一部分,您将看到 synchronized(lock)围绕 head 和 tail 的每次使用,无论同步代码是 wait() 还是 notification()。

如果您自己的代码在调用 wait() 和 notification() 时遵守上述所有三个规则,那么您的程序将更有可能按照您期望的方式运行。

关于Java wait() 不会被 notify() 唤醒,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24655143/

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