7
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()block先进入,notify()ThreadB中的后续会告诉主线程继续。

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

4

3 回答 3

15

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

所以,以下是不行的,因为你说的原因,另一个线程可以在 ThreadA 调用 .wait() 之前调用 .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()将自动释放/重新获取该锁。所以没有竞争条件,如果 .notify() 在我们到达.wait()call 之前被调用,ThreadA 会发现因为donewill betrue并且根本不进入.wait()call 。

对于像这段代码这样的简单情况,你可以等待 ThreadB 结束,可以用b.join();

于 2013-10-23T09:56:41.890 回答
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) {
        }
    }
}
于 2013-10-23T09:46:27.780 回答
0

我猜你想做这样的事情

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);
于 2013-10-23T09:23:33.737 回答