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

3 篇文章 0 订阅
1 篇文章 0 订阅

http://zhangjunhd.blog.51cto.com/113473/71387

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值