天天看點

Java:使用wait()與notify()實作線程間協作

使用wait()與notify()/notifyAll()可以使得多個任務之間彼此協作。

<b>1. wait()</b><b>與</b><b>notify()/notifyAll()</b>

<b></b>

調用sleep()和yield()的時候鎖并沒有被釋放,而調用wait()将釋放鎖。這樣另一個任務(線程)可以獲得目前對象的鎖,進而進入它的synchronized方法中。可以通過notify()/notifyAll(),或者時間到期,從wait()中恢複執行。

隻能在同步控制方法或同步塊中調用wait()、notify()和notifyAll()。如果在非同步的方法裡調用這些方法,在運作時會抛出IllegalMonitorStateException異常。

<b>2.</b><b>模拟單個線程對多個線程的喚醒</b><b></b>

模拟線程之間的協作。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&lt;" + id + "&gt;";

    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&lt;Athlete&gt; players = new HashSet&lt;Athlete&gt;();

    private boolean start = false;

    public void addPlayer(Athlete one) {

      players.add(one);

    public void removePlayer(Athlete one) {

      players.remove(one);

    public Collection&lt;Athlete&gt; 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&lt;Athlete&gt; iter = getPlayers().iterator();

      while (iter.hasNext())

        new Thread(iter.next()).start();

      start = false;

      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 &lt; 10; i++)

        game.addPlayer(new Athlete(i, game));

      new Thread(game).start();

}

結果:

Ready......

Athlete&lt;0&gt; ready!

Athlete&lt;1&gt; ready!

Athlete&lt;2&gt; ready!

Athlete&lt;3&gt; ready!

Athlete&lt;4&gt; ready!

Athlete&lt;5&gt; ready!

Athlete&lt;6&gt; ready!

Athlete&lt;7&gt; ready!

Athlete&lt;8&gt; ready!

Athlete&lt;9&gt; ready!

Go!

Athlete&lt;9&gt; go!

Athlete&lt;8&gt; go!

Athlete&lt;7&gt; go!

Athlete&lt;6&gt; go!

Athlete&lt;5&gt; go!

Athlete&lt;4&gt; go!

Athlete&lt;3&gt; go!

Athlete&lt;2&gt; go!

Athlete&lt;1&gt; go!

Athlete&lt;0&gt; go!

<b>3.</b><b>模拟忙等待過程</b><b></b>

MyObject類的執行個體是被觀察者,當觀察事件發生時,它會通知一個Monitor類的執行個體(通知的方式是改變一個标志位)。而此Monitor類的執行個體是通過忙等待來不斷的檢查标志位是否變化。

BusyWaiting.java

import java.util.concurrent.TimeUnit;

class MyObject implements Runnable {

    private Monitor monitor;

    public MyObject(Monitor monitor) {

      this.monitor = monitor;

      try {

        TimeUnit.SECONDS.sleep(3);

        System.out.println("i'm going.");

        monitor.gotMessage();

        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.");

      watching();

public class BusyWaiting {

      Monitor monitor = new Monitor();

      MyObject o = new MyObject(monitor);

      new Thread(o).start();

      new Thread(monitor).start();

i'm going.

He has gone.

<b>4.</b><b>使用</b><b>wait()</b><b>與</b><b>notify()</b><b>改寫上面的例子</b><b></b>

下面的例子通過wait()來取代忙等待機制,當收到通知消息時,notify目前Monitor類線程。

Wait.java

package concurrency.wait;

        TimeUnit.SECONDS.sleep(3);

        System.out.println("i'm going.");

        monitor.gotMessage();

        e.printStackTrace();

    public synchronized void gotMessage() throws InterruptedException {

      go = true;

      notify();

    public synchronized void watching() throws InterruptedException {

        wait();

        watching();

      } catch (InterruptedException e) {

        e.printStackTrace();

public class Wait {

本文轉自zhangjunhd51CTO部落格,原文連結:http://blog.51cto.com/zhangjunhd/71387,如需轉載請自行聯系原作者