Java notify()在wait()之前运行?

时间:2013-10-23 09:15:36

标签: java multithreading synchronized

public 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){
                e.printStackTrace();
            }

            System.out.println("Total is: " + b.total);
        }
    }
}

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

如上例所示,如果wait()阻止首先进入,则ThreadB中的后续notify()将告诉主线程继续。

但是我们不能保证wait()将在notify(之前执行),如果ThreadB首先进入该块怎么办? Notify()将在wait()之前执行,因此wait()会永远挂在那里(因为没有notify()告诉它继续)?什么通常是处理这个问题的正确方法?

3 个答案:

答案 0 :(得分:9)

你应该几乎总是有一个谓词和wait / notify。也就是说,你需要一个条件 您可以检查,例如变量变为true,队列变为空/满等等。只是盲目地等待某人调用.notify()只有很少的用例。

所以,以下是不行的,因为你说的原因,另一个线程可以在ThreadA调用之前调用.notify()。。()

public class ThreadA {
    public static Object latch = new Object();
    public static void main(String[] args) {
        ThreadB b = new ThreadB();
        b.start();
        synchronized(latch ) {
            latch.wait(); //wait for B to finish a calculation
        }
        System.out.println("Total is: " + b.total);

    }
}

class ThreadB extends Thread {
    int total;

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            total += i;
        }
       synchronized(ThreadA.latch) {
           ThreadA.latch.notify();
       }
    }
}

你需要做这样的事情:

 public class ThreadA {
    public static Object latch = new Object();
    public static boolean done = false;
    public static void main(String[] args) {
        ThreadB b = new ThreadB();
        b.start();
        synchronized(latch ) {
            while (!done) {   //wait for B to indicate it is finished.
                latch.wait(); 
            }
        }
        System.out.println("Total is: " + b.total);

    }
}

class ThreadB extends Thread {
    int total;

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            total += i;
        }
       synchronized(ThreadA.latch) {
           ThreadA.done = true;         
           ThreadA.latch.notify();
       }
    }
}

请注意,在上面,done变量受同步块保护,.wait()将自动释放/重新获取该锁定。所以没有竞争条件,如果在我们进入.wait()调用之前调用.notify(),ThreadA会发现因为done将是true而不进入{{ 1}}打电话。

对于像这段代码这样的简单案例,您可以等待ThreadB结束,可以使用.wait()

完成

答案 1 :(得分:1)

我想你想做这样的事情

public class ThreadA {
    public static void main(String[] args) {
        ThreadB b = new ThreadB();
        b.start();
        b.join(); // Wait for thread b to finish 

        System.out.println("Total is: " + b.total);

    }
}

您还应该让ThreadB只实现Runnable而不是扩展Thread

class ThreadB implements Runnable {
    int total;

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

然后使用它

ThreadB tb = new ThreadB();
Thread b = new Thread(tb);

答案 2 :(得分:1)

您的问题的许多可能解决方案之一是:

public class ThreadA {
  public static final CyclicBarrier barrier = new CyclicBarrier(2);

  public static void main(String[] args) {
    ThreadB b = new ThreadB();
    b.start();
    try {
      barrier.await();
      System.out.println("Total is: " + b.total);
    } catch (InterruptedException | BrokenBarrierException ex) {
    }
  }
}

class ThreadB extends Thread {
    int total;

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            total += i;
        }
        try {
          ThreadA.barrier.await();
        } catch (InterruptedException | BrokenBarrierException ex) {
        }
    }
}