确保在线程中的notify()之前调用wait(),是否可能?

时间:2013-04-12 19:36:35

标签: java thread-safety race-condition

当我遇到使用wait / notify方法的示例时,我正在查看Kathy Sierra书中的Threading章节:

 class ThreadA {
 public static void main(String [] args) {
 ThreadB b = new ThreadB();
 b.start();

 synchronized(b) {
 try {
    System.out.println("Waiting for b to complete...");
    b.wait();
     } catch (InterruptedException e) {}
 System.out.println("Total is: " + b.total);
 }
}
}

class ThreadB extends Thread { 
 int total;
 public void run() {
  synchronized(this) {
   for(int i=0;i<100;i++) {
   total += i;
   }
  notify();
 }
}
}

运行代码始终产生相同的输出:

  

等待b完成......总计是:4950

我通过添加:

修改了ThreadB中run()的synchronized块
System.out.println("ThreadB is executed"); 

问题是:为什么我要继续

  

“等待b完成......”

之前

  

“执行ThreadB”

?是不是有可能在主线程之前执行线程b?

2 个答案:

答案 0 :(得分:5)

  

是否有可能在主要之前执行线程b   线程?

是的,绝对。

通常wait会附带一些谓词以防止出现此类问题。

例如,ThreadB可以有一个变量表示它已完成。在您的情况下,您可以检查总计不是0。

synchronized (b) {
    try {
        System.out.println("Waiting for b to complete...");
        while (b.total == 0) {
            b.wait();
        }
    } catch (InterruptedException e) {
    }
    System.out.println("Total is: " + b.total);
}

这会在读取与ThreadB中的写入相关的总计上创建一个先发生的关系。

答案 1 :(得分:5)

  

是否有可能在主线程之前执行线程b?

是的,存在这种可能性,尽管这种可能性很小,例如这段代码中的那种。

代码在获取b的监视器(同步块)之前调用b.start()。主线程有可能在该窗口期间被抢占,并且线程B将首先运行并获取该监视器。

在这种情况下,这个程序会挂起,因为主线程永远wait(),因为它错过了线程B中的notify()