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

a.u*_*u.r 0 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();
 }
}
}
Run Code Online (Sandbox Code Playgroud)

运行代码总是产生相同的输出:

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

我在ThreadB中修改了run()的synchronized块,添加:

System.out.println("ThreadB is executed"); 
Run Code Online (Sandbox Code Playgroud)

问题是:我为什么一直这样做

"等待b完成......"

之前

"执行ThreadB"

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

Joh*_*int 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);
}
Run Code Online (Sandbox Code Playgroud)

这会在读取总计时创建与ThreadB中的写入相关的先发生关系.

  • @aur在我看来,你读过的书不遵循这种并发习惯是不负责任的. (2认同)

van*_*nza 5

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

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

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

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

  • +1还要注意一个垂死的线程自己调用`notifyAll`--这就是`join`的实现方式. (2认同)