Java等待/通知-未唤醒线程
我正试着做一个小练习来习惯等待/通知。 我试图做的是简单地启动一个线程,然后让它在等待中休眠,然后在通知中唤醒它,多次 我的代码是:Java等待/通知-未唤醒线程,java,multithreading,wait,notify,Java,Multithreading,Wait,Notify,我正试着做一个小练习来习惯等待/通知。 我试图做的是简单地启动一个线程,然后让它在等待中休眠,然后在通知中唤醒它,多次 我的代码是: 公共类简单{ 静态最终线程mainThread=Thread.currentThread(); 公共静态void main(字符串[]args)引发InterruptedException{ PrintThread打印机=新的PrintThread(0); printer.start(); 已同步(主线程){ System.out.println(“等待打印机启动
公共类简单{
静态最终线程mainThread=Thread.currentThread();
公共静态void main(字符串[]args)引发InterruptedException{
PrintThread打印机=新的PrintThread(0);
printer.start();
已同步(主线程){
System.out.println(“等待打印机启动时主休眠”);
mainThread.wait();
System.out.println(“主唤醒”);
对于(int i=0;i<1000;i++){
同步(打印机){
System.out.println(“添加的数值”+i);
printer.numToPrint=i;
System.out.println(“主唤醒打印机”);
printer.notifyAll();
System.out.println(“主睡眠”);
mainThread.wait();
System.out.println(“主唤醒”);
}
}
}
}
}
类PrintThread扩展线程{
公共int numToPrint=-1;
公共打印线程(int numToPrint){
this.numToPrint=numToPrint;
}
@凌驾
公共同步的无效运行(){
System.out.println(“打印机已启动”);
while(true){
试一试{
已同步(Simple.mainThread){
System.out.println(“打印机唤醒主”);
Simple.mainThread.notifyAll();
}
System.out.println(“打印机休眠”);
等待();
System.out.println(“打印机唤醒”);
}捕捉(中断异常e){
e、 printStackTrace();
}
System.out.println(“printing num”+numToPrint);
}
}
}
我希望事情会像这样发展
main sleeping while waiting for printer to be started
printer started
printer waking up main
printer sleeping
main woke up
added num 0
main waking up printer
main sleeping
printer woke up
printing num 0
printer waking up main
printer sleeping
main woke up
added num 1
...
而是:
main sleeping while waiting for printer to be started
printer started
printer waking up main
printer sleeping
main woke up
added num 0
main waking up printer
main sleeping
所以。。。好像notify没有唤醒打印机线程
它不应该是一个死锁,因为通过等待我可以解除所有的锁定,因此主不应该对打印机有任何锁定,并且打印机应该能够唤醒并打印
我做错了什么?很可能是在再次调用Print calls wait()之前调用了notifyAll()调用。问题在于您对等待和通知的依赖,所有调用都是按照您希望的顺序进行的。这是两个不同的执行线程,所以当然这不是保证,因此您得到的是您已经得到的
实现这一点的更好方法是创建一个公共的第三共享对象,两个线程都可以获得锁定。这将使两个线程在等待访问此对象时同步
此外,您还应该阅读Thread.wait、notify和notifyAll的Javadocs。如果/当您这样做时,您将看到您永远不应该在线程上调用这些方法,因为它们用于执行thread.join(不仅如此,还包括我的“声名远播”)我相信这是我多年前的错误请求,当它不在JavaDoc中时,它被添加到JavaDoc中。可能是其他人,但它发生在我请求之后:)属性:调用wait()释放锁(它正在监视)并进入等待状态。它在同一对象上等待notify()或notifyAll()。一旦notify()或notifyAll()在CPU中得到调度,它将在恢复之前再次获取锁 当您在main方法中第一次执行“synchronized(mainThread)”时,它基本上锁定了“mainThread”类对象。调用mainThread.wait()时,mainThread处于等待状态(等待有人在mainThread类对象上调用notify或notifyAll) 此时,PrintThread可能会获得CPU。这是“synchronized(Simple.mainThread)”被调度并锁定“Simple.mainThread”并通知所有等待“Simple.mainThread”的线程的时候。在这个块完成后,PrintThread释放“Simple.mainThread”锁 此时,主线程将再次尝试获取“主线程”上的锁,然后从调用wait的位置恢复。因为此时未获取“mainThread”锁,所以主线程获取锁并打印“mainwakeup” 现在,这里遇到了for循环。 记住:这里已经获得了对“mainThread”类对象的锁定 现在在for循环内部,它获得了对“printer”对象的锁定。执行一些计算并调用“printer.notifyAll()”,所有等待“printer”对象的线程都将得到通知 **这里要记住的一点是:由于代码光标仍在“synchronized(printer)”内,所以尚未释放对“printer”对象的锁定** 向前看,将打印“main sleeping”,然后调用“mainThread.wait()”。这将尝试获取已获取的“mainThread”上的锁(如上所述,其中“记住:”在块中),并被卡住,因为此后没有线程在“mainThread”上进行通知,“synchronized(printer)”块永远不会结束,即即使在调用NotifyAll()之后,“printer”对象上的锁也永远不会解除 尝试在开始时在main方法中添加以下代码,以测试上述场景。
synchronized (mainThread) {
synchronized (printer){
System.out.println("Before");
mainThread.wait();
System.out.println("After");
}
解决方案:
在“printer.notifyAll()”之后关闭“synchronized(printer)”块,以便在通知之后和获取“main thread”之前释放“printer”锁。Mhh。。。这是有道理的,如果主调用在打印机进入睡眠前通知,那么整个程序将被阻止。但是输出说等待首先被调用。。。那么,是否有可能等待开始执行,但在通知开始之前不结束执行?@FedericoSpece,正如我所说,你这样做是错误的,你永远不会把它发送给w