注册 | 登录 忘记密码? 51cto首页 | 博客 | 论坛 | 招聘
热点文章 35岁技术人遭遇年龄坎儿,..
 帮助

Java:使用wait()与notify()实现线程间协作


2008-04-13 20:34:19
版权声明:原创作品,如需转载,请与作者联系。否则将追究法律责任。
使用wait()notify()/notifyAll()可以使得多个任务之间彼此协作。
1. wait()notify()/notifyAll()
调用sleep()yield()的时候锁并没有被释放,而调用wait()将释放锁。这样另一个任务(线程)可以获得当前对象的锁,从而进入它的synchronized方法中。可以通过notify()/notifyAll(),或者时间到期,从wait()中恢复执行。
只能在同步控制方法或同步块中调用wait()notify()notifyAll()。如果在非同步的方法里调用这些方法,在运行时会抛出IllegalMonitorStateException异常。
2.模拟单个线程对多个线程的唤醒
模拟两个线程之间的协作。Athele类有两个同步方法prepare()go()。标志位start用于判断当前线程是否需要wait()Referee类的实例首先启动所有的Athele类实例,使其进入wait()状态,在一段时间后,改变标志位并notifyAll()所有处于wait状态的Athele线程。
Game.java
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.TimeUnit;
 
class Athlete implements Runnable {
    private boolean start = false;
    private final int id;
 
    public Athlete(int id) {
       this.id = id;
    }
 
    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 synchronized void prepare() throws InterruptedException {
       System.out.println(this + " ready!");
       while (start == false)
           wait();
       if (start == true)
           System.out.println(this + " go!");
    }
 
    public synchronized void go() {
       start = true;
       notifyAll();
    }
 
    public void run() {
       try {
           prepare();
       } catch (InterruptedException e) {
           //maybe should notify the referee
           System.out.println(this+" quit the game");
       }
    }
}
 
class Referee implements Runnable {
    private Set<Athlete> players = new HashSet<Athlete>();
 
    public void addPlayer(Athlete one) {
       players.add(one);
    }
 
    public void removePlayer(Athlete one) {
       players.remove(one);
    }
 
    public void ready() {
       Iterator<Athlete> iter = players.iterator();
       while (iter.hasNext())
           new Thread(iter.next()).start();
    }
 
    public void action() {
       Iterator<Athlete> iter = players.iterator();
       while (iter.hasNext())
           iter.next().go();
    }
 
    public void run() {
       ready();
       try {
           TimeUnit.SECONDS.sleep(1);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
       action();
    }
}
 
public class Game {
    public static void main(String[] args) {
       Referee referee = new Referee();
       for (int i = 0; i < 10; i++)
           referee.addPlayer(new Athlete(i));
       new Thread(referee).start();
    }
}
结果:
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!
Athlete<0> go!
Athlete<1> go!
Athlete<2> go!
Athlete<3> go!
Athlete<4> go!
Athlete<5> go!
Athlete<6> go!
Athlete<7> go!
Athlete<8> go!
Athlete<9> go!
3.模拟忙等待过程
MyObject类的实例是被观察者,当观察事件发生时,它会通知一个Monitor类的实例(通知的方式是改变一个标志位)。而此Monitor类的实例是通过忙等待来不断的检查标志位是否变化。
BusyWaiting.java
package com.zj.busywaiting;
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 com.zj.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.

本文出自 “子 孑” 博客,转载请与作者联系!


附件下载:
  Game.java
  BusyWaiting.java
  Wait.java