文章对此进行了如下说明: 不带参数的等待方法 导致当前线程等待,直到另一个线程调用此对象的 notify() 方法或 notifyAll() 方法。换句话说,这个方法的行为就像它只是在做一个 wait(0) 调用一样。 https://java-en-blog.blogspot.com/2019/12/object-methods.html
有一个代码:
public class Main {
public static void main(String[] args) {
ThreadB threadB = new ThreadB();
threadB.start();
synchronized (threadB){
try {
threadB.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(threadB.total);
}
}
class ThreadB extends Thread {
int total;
@Override
public void run() {
for (int i = 0; i < 5; i ++){
total+=i;
try {
sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/* synchronized (this){
notify();
}*/
}
}
一下子有两个问题:
- 即使 notify() 方法被注释掉,线程也会运行到最后,这与上面写的内容相矛盾。
- 如果取消注释notify(),就不是很清楚为什么调用这个方法是在线程内部(线程如何唤醒自己)
等待方法的文档说:
这是惯用的使用方式
wait- 始终在循环中,并在调用之前和之后检查条件wait。因为 你有一个综合的例子,很难说这里的条件是什么。对于订阅方的经典发布-订阅示例,等待条件为пока нет входящих сообщений.总而言之,问题在于虚假唤醒,即 在不合理的觉醒中。那些。
wait即使没有 . 也可以返回控制权notify。好吧,这就是你写它的方式:) 通常,对象不用于等待
Thread,而是使用其他对象。通常这是线程之间共享的对象,它也用于发送通知。在与publish-相同的示例中,subscribe它可以是传输通知的队列。至少在这里看到一个适当的例子
我不是超级精通java,但我想当线程停止执行时调用Notify是Thread类的一个特性。也就是说,在您的代码中,主线程首先停止,然后子线程开始工作,当它完成时,它会在没有您参与的情况下自行调用通知,这将解锁主线程。要测试这个理论,请尝试注释掉 threadB.start(); 你的程序应该挂起,因为子线程永远不会完成它的工作(因为它甚至还没有启动它),这意味着它永远不会解除对主线程的阻塞。
为了进行更干净的实验,我们不要锁定流对象,而只是锁定其他对象。例如
我认为在这里,如果您注释掉该行,
Solution.syncRoot.notify();程序将按预期挂起。