>>分享Java编程技术,对《Java面向对象编程》等书籍提供技术支持 书籍支持  卫琴直播  品书摘要  在线测试  资源下载  联系我们
发表一个新主题 开启一个新投票 回复文章 您是本文章第 30729 个阅读者 刷新本主题
 * 贴子主题:  使用wait()与notify()实现线程间协作 回复文章 点赞(0)  收藏  
作者:flybird    发表时间:2020-01-08 08:08:07     消息  查看  搜索  好友  邮件  复制  引用

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

1. wait() notify()/notifyAll()<o:p></o:p>

  调用 sleep() 和 yield() 的时候锁并没有被释放,而调用 wait() 将释放锁。这样另一个任务(线程)可以获得当前对象的锁,从而进入它的 synchronized 方法中。可以通过 notify()/notifyAll() ,或者时间到期,从 wait() 中恢复执行。

  只能在同步控制方法或同步块中调用 wait() 、 notify() 和 notifyAll() 。如果在非同步的方法里调用这些方法,在运行时会抛出 IllegalMonitorStateException 异常。

2. 模拟单个线程对多个线程的唤醒 <o:p></o:p>

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

<u> Game.java</u>  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!
   <o:p></o:p>

3. 模拟忙等待过程 <o:p></o:p>

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

<u> BusyWaiting.java</u>  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. <o:p></o:p>

  He has gone.

4. 使用 wait() notify() 改写上面的例子 <o:p></o:p>

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

<u> Wait.java</u>  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. <o:p></o:p>

  He has gone.


----------------------------
原文链接:https://blog.51cto.com/zhangjunhd/71387

程序猿的技术大观园:www.javathinker.net



[这个贴子最后由 flybird 在 2020-01-08 15:10:15 重新编辑]
  Java面向对象编程-->面向对象开发方法概述之UML语言(下)
  JavaWeb开发-->面向对象开发方法概述之UML语言(下)
  JSP与Hibernate开发-->Web运作原理(Ⅱ)
  Java网络编程-->自定义JSP标签(Ⅱ)
  精通Spring-->映射对象标识符
  Vue3开发-->映射对象标识符
  java的三种随机数生成方式
  NIO底层原理
  Java设计模式: 单一职责原则和依赖倒置原则详解
  JAVA锁相关知识总结
  Java并发编程的总结与思考
  使用策略模式优化代码实践,如何让项目快速起飞
  JDBC API中的桥接模式
  小数在内存中是如何存储的?
  Java多线程volatile详解
  java比c++强大之处JVM垃圾收集算法
  Java入门实用代码:自定义异常
  Java 入门实用代码:数组扩容
  正则表达式【匹配非字母和数字】
  Java程序代码优化技巧
  Java中的main()方法详解
  更多...
 IPIP: 已设置保密
楼主      
1页 0条记录 当前第1
发表一个新主题 开启一个新投票 回复文章


中文版权所有: JavaThinker技术网站 Copyright 2016-2026 沪ICP备16029593号-2
荟萃Java程序员智慧的结晶,分享交流Java前沿技术。  联系我们
如有技术文章涉及侵权,请与本站管理员联系。