线程notifyAll()

时间:2016-07-28 04:21:06

标签: java multithreading

给定一个线程有多个状态:alive runnable运行等待和终止。 notifyAll()方法假设将所有“等待”对象锁定的线程放回“runnable”状态,在该状态下可以选择它作为下一个运行对象。 下面的示例实例化并启动3个Reader线程,这些线程进入等待(wait()方法),直到'calc'对象的锁被释放。 calc对象线程被实例化并在此之后启动,它会添加一些数字,然后是notifyAll()。

我的问题是,为什么calc线程每次都不会通知所有的Reader线程?当我在我的电脑上运行它时,它会被击中并错过。

public class Reader extends Thread{
    Calculator c;

    public Reader(Calculator calc){
        c=calc;
    }

    public void run(){
        synchronized(c){
            try{
                System.out.println("Waiting for calculation...");
                c.wait();
            }catch(InterruptedException e){}
            System.out.println("Total is: "+c.total);
        }
    }
    public static void main(String[] args){
        Calculator calc = new Calculator();
        new Reader(calc).start();
        new Reader(calc).start();
        new Reader(calc).start();
        new Thread(calc).start();
    }
}
class Calculator implements Runnable{
    int total;

    public void run(){
        synchronized(this){
            for(int i =0; i<100; i++){
                total+=i;
            }
            notifyAll();
        }
    }
}

2 个答案:

答案 0 :(得分:1)

执行多个线程时,线程的执行顺序保证。

在你的情况下,即使在任何Calculator线程进入可运行状态之前,notifyAll()线程也可能完成它的循环并调用Reader。因此,所有Reader都会一直等待,永远不会打印total

为避免这种情况,在此特定示例中,您可以在isCalculated中使用另一个标志Calculator,并在计算完成后设置此标志。 Reader个帖子也会检查此标记,并仅在isCalculatedfalse时等待。

class Reader extends Thread {
  Calculator c;

  public Reader(Calculator calc) {
    c = calc;
  }

  public void run() {
    synchronized (c) {
      try {
        System.out.println("Waiting for calculation...");

        if (!c.isCalculated) { // wait only if calculation is not done
          c.wait();
        }
      } catch (InterruptedException e) {
      }
      System.out.println("Total is: " + c.total);
    }
  }
}

class Calculator implements Runnable {
  int total;
  boolean isCalculated;

  public void run() {
    synchronized (this) {
      for (int i = 0; i < 100; i++) {
        total += i;
      }

      isCalculated = true;  // set flag to mark that computation is complete
      notifyAll();
    }
  }
}

答案 1 :(得分:0)

如@Sudhir所述,您可以在调用wait之前检查一些标志, 查看本教程:http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html

在你的情况下,可以在调用wait之前调用notifyAll()..因此线程可能会一直等待调用通知