使用
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.