Java notify()在wait()之前运行?
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()
告诉它继续)? 处理这个问题的正确方法通常是什么?
你应该几乎总是有一个谓词和wait / notify。 也就是说,您需要一个可以检查的条件,例如变量变为true,队列变为空/满等等。只是盲目地等待某人调用.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
变量受synchronized块保护, .wait()
将自动释放/重新获取该锁。 因此没有竞争条件,并且如果在我们到达.wait()
调用.wait()
,则ThreadA将发现因为done
将为true
而根本不进入.wait()
调用。
对于像这个代码这样的简单情况,你可以等待ThreadB结束,可以用b.join();
我想你想做这样的事情
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);
您问题的众多可能解决方案之一是:
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) { } } }