为什么线程不等待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();
}
}
}
答案 0 :(得分:7)
您正在同步线程对象本身,这是错误的用法。发生的事情是,垂死的执行线程总是在其notify
对象上调用Thread
:Thread.join
relies on this。因此,很清楚为什么在使用和不使用自己的notify
时会得到相同的行为。
解决方案:使用单独的对象进行线程协调;这是标准做法。
答案 1 :(得分:2)
为终止线程的notifyAll()
对象调用方法Thread
。这个事实在Thread.join
的描述中有奇怪的记载,并带有以下句子:
当一个线程终止时,将调用this.notifyAll方法。建议应用程序不要在Thread实例上使用wait,notify或notifyAll。
因此,如果你没有明确阅读join
的描述,你不一定要这样做,你就不会知道这种奇怪行为的原因。
答案 2 :(得分:1)
你不能依赖于从等待直到通知回来:“中断和虚假唤醒是可能的”。通常,你应该在循环中包含一个等待调用,而线程应该继续等待。
答案 3 :(得分:1)
如果您尝试在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源代码)
正如您所看到的,对wait
的调用只有在线程结束后调用notify
的某个地方时才有意义。对notify
的同一调用是允许程序终止的原因。
答案 4 :(得分:0)
您在两个地方嵌套了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()调用来自何处。
答案 5 :(得分:0)
我在读取OCP SE 7时对wait / notify操作进行了相同的测试,很好的捕获。我想我们应该让authoer解释一下。