为什么没有线程等待notify()?
为什么没有线程等待notify()
? 线程启动然后进入等待池,但是在那之后它继续执行。
public class JavaApplication2 { public static void main(String [] args) { ThreadB b = new ThreadB(); synchronized(b) { b.start(); try { System.out.println("1"); b.wait(); } catch (InterruptedException e) {} System.out.println("Total is: " + b.total); } } } class ThreadB extends Thread { int total; @Override public void run() { synchronized(this) { total += 1; //notify(); } } }
您正在同步线程对象本身,这是错误的用法。 发生的事情是,垂死的执行线程总是在其Thread
对象上调用notify
: Thread.join
依赖于此 。 因此很清楚为什么在那里使用和不使用自己的notify
会得到相同的行为。
解决方案:使用单独的对象进行线程协调; 这是标准做法。
为终止线程的Thread
对象调用方法notifyAll()
。 这个事实在Thread.join
的描述中有奇怪的记录,使用以下句子:
当一个线程终止时,将调用this.notifyAll方法。 建议应用程序不要在Thread实例上使用wait,notify或notifyAll。
因此,如果您没有明确阅读您不一定需要的join
描述,则无法了解奇怪行为的原因。
你不能依赖于等待直到通知:“中断和虚假唤醒是可能的”。 通常,您应该在循环中包含等待调用,而线程应该继续等待。
如果您尝试在ThreadB
任何对象上同步代码,您将发现它永远不会终止。 这是因为有一个隐藏的notify
。
虽然我不知道任何指定的内容,但Thread会在结束时通知自己。 这是实现join
方法的隐含方式。 这是join
的代码:
public final synchronized void join(long millis) throws InterruptedException { long base = System.currentTimeMillis(); long now = 0; if (millis < 0) { throw new IllegalArgumentException("timeout value is negative"); } if (millis == 0) { while (isAlive()) { wait(0); } } else { while (isAlive()) { long delay = millis - now; if (delay <= 0) { break; } wait(delay); now = System.currentTimeMillis() - base; } } }
(来自JDK7源代码)
正如您所看到的,只有在线程结束后调用notify
某个地方,才会发出wait
调用。 同一个notify
调用是允许程序终止的。
您在两个位置嵌套了synchronized {}构造。 这些构造似乎做了一些奇怪的事情:线程根本没有对notify进行反应,只在ThreadB(b)终止时才恢复。 删除这个:
public class JavaApplication2 { public static void main(String[] args) { ThreadB b = new ThreadB(); b.start(); try { System.out.println(" ### Waiting for notify"); synchronized (b) { b.wait(); } System.out.println(" ### Notified"); } catch (InterruptedException e) { } System.out.println("### Total is: " + b.total); } } class ThreadB extends Thread { int total; @Override public void run() { total += 1; System.out.println(" *** Ready to notify in 5 secs"); try { Thread.sleep(5000); } catch (InterruptedException e) { } System.out.println(" *** Notification sent"); synchronized (this) { notify(); } System.out.println(" *** 5 sec post notification"); try { Thread.sleep(5000); } catch (InterruptedException e) { } System.out.println(" *** ThreadB exits"); } }
上面的代码可能正常工作:使用notify(),主线程在5秒后恢复,然后我们看到ThreadB终止的消息。 随着notify()被注释掉,主线程在10秒之后和关于ThreadB终止的消息之后恢复,因为notify()从其他代码调用anywhay。 Marko Topolnik解释了为什么以及这个“幕后”notify()调用的来源。
我正在读取OCP SE 7时对wait / notify操作进行相同的测试,这很好。 我想我们应该让authoer解释一下。