使用 wait() notify()/notifyAll() 可以使得多个任务之间彼此协作。
1. wait() notify()/notifyAll()

调用 sleep() yield() 的时候锁并没有被释放,而调用 wait() 将释放锁。这样另一个任务(线程)可以获得当前对象的锁,从而进入它的 synchronized 方法中。可以通过 notify()/notifyAll() ,或者时间到期,从 wait() 中恢复执行。
只能在同步控制方法或同步块中调用 wait() notify() notifyAll() 。如果在非同步的方法里调用这些方法,在运行时会抛出 IllegalMonitorStateException 异常。
2. 模拟单个线程对多个线程的唤醒

模拟线程之间的协作。Game 类有2个同步方法 prepare() go() 。标志位 start 用于判断当前线程是否需要 wait() 。Game 类的实例首先启动所有的 Athele 类实例,使其进入 wait() 状态,在一段时间后,改变标志位并 notifyAll() 所有处于 wait 状态的 Athele 线程。
Game.java
package concurrency;

import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

class Athlete implements Runnable {
     private final int id;
     private Game game;

     public Athlete( int id, Game game) {
      this.id = id;
      this.game = game;
    }

     public boolean equals(Object o) {
      if (!(o instanceof Athlete))
        return false;
      Athlete athlete = (Athlete) o;
      return id == athlete.id;
    }

     public String toString() {
      return "Athlete<" + id + ">";
    }

     public int hashCode() {
      return new Integer(id).hashCode();
    }

     public void run() {
      try {
        game.prepare( this);
      } catch (InterruptedException e) {
        System.out.println( this + " quit the game");
      }
    }
  }

public class Game implements Runnable {
     private Set<Athlete> players = new HashSet<Athlete>();
     private boolean start = false;

     public void addPlayer(Athlete one) {
      players.add(one);
    }

     public void removePlayer(Athlete one) {
      players.remove(one);
    }

     public Collection<Athlete> getPlayers() {
      return Collections.unmodifiableSet(players);
    }

     public void prepare(Athlete athlete) throws InterruptedException {
      System.out.println(athlete + " ready!");
      synchronized ( this) {
        while (!start)
        wait();
        if (start)
          System.out.println(athlete + " go!");
      }
    }

     public synchronized void go() {
      notifyAll();
    }
    
     public void ready() {
      Iterator<Athlete> iter = getPlayers().iterator();
      while (iter.hasNext())
        new Thread(iter.next()).start();
    }

     public void run() {
      start = false;
      System.out.println( "Ready......");
      System.out.println( "Ready......");
      System.out.println( "Ready......");
      ready();
      start = true;
      System.out.println( "Go!");
      go();
    }

     public static void main(String[] args) {
      Game game = new Game();
      for ( int i = 0; i < 10; i++)
        game.addPlayer( new Athlete(i, game));
      new Thread(game).start();
    }
}
结果:
Ready......
Ready......
Ready......
Athlete<0> ready!
Athlete<1> ready!
Athlete<2> ready!
Athlete<3> ready!
Athlete<4> ready!
Athlete<5> ready!
Athlete<6> ready!
Athlete<7> ready!
Athlete<8> ready!
Athlete<9> ready!
Go!
Athlete<9> go!
Athlete<8> go!
Athlete<7> go!
Athlete<6> go!
Athlete<5> go!
Athlete<4> go!
Athlete<3> go!
Athlete<2> go!
Athlete<1> go!
Athlete<0> go!

3. 模拟忙等待过程

MyObject 类的实例是被观察者,当观察事件发生时,它会通知一个 Monitor 类的实例(通知的方式是改变一个标志位)。而此 Monitor 类的实例是通过忙等待来不断的检查标志位是否变化。
BusyWaiting.java
import java.util.concurrent.TimeUnit;

class MyObject implements Runnable {
     private Monitor monitor;

     public MyObject(Monitor monitor) {
      this.monitor = monitor;
    }

     public void run() {
      try {
        TimeUnit.SECONDS.sleep(3);
        System.out.println( "i'm going.");
        monitor.gotMessage();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
}

class Monitor implements Runnable {
     private volatile boolean go = false;

     public void gotMessage() throws InterruptedException {
      go = true;
    }

     public void watching() {
      while (go == false)
        ;
      System.out.println( "He has gone.");
    }

     public void run() {
      watching();
    }
}

public class BusyWaiting {
     public static void main(String[] args) {
      Monitor monitor = new Monitor();
      MyObject o = new MyObject(monitor);
      new Thread(o).start();
      new Thread(monitor).start();
    }
}
结果:
i'm going.

He has gone.
4. 使用 wait() notify() 改写上面的例子

下面的例子通过 wait() 来取代忙等待机制,当收到通知消息时, notify 当前 Monitor 类线程。
Wait.java
package concurrency.wait;

import java.util.concurrent.TimeUnit;

class MyObject implements Runnable {
     private Monitor monitor;

     public MyObject(Monitor monitor) {
      this.monitor = monitor;
    }

     public void run() {
      try {
        TimeUnit.SECONDS.sleep(3);
        System.out.println( "i'm going.");
        monitor.gotMessage();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
}

class Monitor implements Runnable {
     private volatile boolean go = false;

     public synchronized void gotMessage() throws InterruptedException {
      go = true;
      notify();
    }

     public synchronized void watching() throws InterruptedException {
      while (go == false)
        wait();
      System.out.println( "He has gone.");
    }

     public void run() {
      try {
        watching();
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
}

public class Wait {
     public static void main(String[] args) {
      Monitor monitor = new Monitor();
      MyObject o = new MyObject(monitor);
      new Thread(o).start();
      new Thread(monitor).start();
    }
}
结果:
i'm going.

He has gone.