为什么没有线程等待notify()?

时间:2013-01-06 21:16:09

标签: java concurrency wait 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();
       }
    }
 }

6 个答案:

答案 0 :(得分:7)

您正在同步线程对象本身,这是错误的用法。发生的事情是,垂死的执行线程总是在其notify对象上调用ThreadThread.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解释一下。