4

为什么线程不等待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();
       }
    }
 }
4

6 回答 6

7

您正在对线程对象本身进行同步,这是错误的用法。发生的事情是垂死的执行线程总是调用notify它的Thread对象:Thread.join 依赖于 this。因此,很清楚为什么在有和没有你自己notify的情况下你会得到相同的行为。

解决方案:使用单独的对象进行线程协调;这是标准做法。

于 2013-01-06T21:42:43.143 回答
2

为终止线程notifyAll()的对象调用该方法。Thread这一事实奇怪地记录在 的描述中Thread.join,并附有以下句子:

当线程终止时,将调用 this.notifyAll 方法。建议应用程序不要在 Thread 实例上使用 wait、notify 或 notifyAll。

因此,如果您没有明确阅读 的描述(join不一定必须阅读),您就不会知道奇怪行为的原因。

于 2014-04-25T12:58:10.283 回答
1

您不能依赖于不从等待直到通知返回:“中断和虚假唤醒是可能的”。通常,您应该将等待调用包装在一个循环中,而线程应该继续等待。

于 2013-01-06T21:20:58.803 回答
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是允许您的程序终止的原因。

于 2013-01-06T23:25:55.237 回答
0

您在这两个地方嵌套了同步 {} 构造。这些结构似乎在做一些奇怪的事情:线程根本不会对通知做出反应,只有在 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() 是从其他代码调用的。Marko Topolnik 解释了这个“幕后” notify() 调用的原因和来源。

于 2013-01-06T21:59:56.943 回答
0

我在阅读 OCP SE 7 时对等待/通知操作进行了相同的测试,很好。我想我们应该让作者解释一下。

于 2016-03-23T03:44:38.640 回答