文档章节

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

We911
 We911
发布于 2017/02/08 10:12
字数 895
阅读 2
收藏 0
Java:使用wait()与notify()实现线程间协作

原创作品,允许转载,转载时请务必以超链接形式标明文章  原始出处 、作者信息和本声明。否则将追究法律责任。 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();
    }
}

本文转载自:http://blog.csdn.net/liduanw/article/details/8203474

共有 人打赏支持
We911
粉丝 1
博文 63
码字总数 0
作品 0
深圳
程序员
Java编程的逻辑 -- 并发章 -- 线程的基本协作机制

线程的基本协作 线程的基本协作示例 总结 线程的基本协作 多线程间除了竞争访问同一资源外,也经常需要相互协作的去执行一些任务。而对于协作的基本机制用的最多的无疑是wait/notify。 协作的...

HikariCP
06/22
0
0
Java多线程学习(四)等待/通知(wait/notify)机制

系列文章传送门: Java多线程学习(一)Java多线程入门 Java多线程学习(二)synchronized关键字(1) java多线程学习(二)synchronized关键字(2) Java多线程学习(三)volatile关键字 Ja...

一只蜗牛呀
04/16
0
0
java并发编程(2)——wait和notify解析

JAVA的进程同步是通过synchronized()来实现的,需要说明的是,JAVA的synchronized()方法类似于操作系统概念中的互斥内存块,在JAVA中的Object类型中,都是带有一个内存锁的,在有线程获取该内...

十二缸帕萨特
2014/04/12
0
0
多线程编程学习三(线程间通信).

一、概要 线程是操作系统中独立的个体,但这些个体如果不经过特殊的处理就不能成为一个整体,线程间的通信就是成为整体的必用方案之一。可以说,使线程进行通信后,系统之间的交互性会更强大...

jmcui
2017/09/12
0
0
《java7核心技术与最佳实践》读书笔记之 multi-thread (2)

基本thread的同步方式 对于多thread中存在的数据竞争,需要利用java平台提供的同步机制来确保对共享变量的访问存在合适的“在之前发生”(happens-before)的顺序。java平台提供的基本同步方...

laserdance
2014/03/24
0
1

没有更多内容

加载失败,请刷新页面

加载更多

下一页

谷歌 Fuchsia 上手体验,将取代Android/win10

在手机市场领域,Google表现很抢眼,毫无疑问,Android 至今在移动操作系统的市场份额占据绝对领先地位,但是 Android 仍然存在不少问题,碎片化问题严重,在平板以及大屏幕设备上表现糟糕,...

linux-tao
27分钟前
1
0
List、Array与ArrayList

数组在内存中是连续存储的,所以它的索引速度很快,而且赋值和修改元素也非常快,比如: string[] s=new string[3];//赋值 s[0]="a"; s[1]="b"; s[2]="c";//修改 s[1]="b1"; 但是数组...

shimmerkaiye
30分钟前
0
0
Linux 的Lnmp环境下为mysql添加环境变量

一.问题 在Linux 安装完Lnmp 环境后 , 连接Mysql 告诉没有这条命令 mysql -uroot -p 命令失效 因为是源码安装的,所以会出现这样的的原因 。集成环境是不会出现的。 其实很简单,只需要给m...

15834278076
32分钟前
3
0
apolloxlua include函数

include函数不是单独使用的函数, 他并不是标准库的一部分, 你可以使用include函数将某个后缀为 .aop的文档包含到你的文档流中。 因为include是单独处理流, 所以不会在主处理流程中有所表示...

钟元OSS
36分钟前
0
0
【转载分享】做一名较真的工程师

近些年与我共事过的同事,一定知道我至今仍有一个较真的性格。我会:指出同事所写代码的不当命名问题(并帮助改进);指出同事所写文档中的逻辑混乱问题(并辅以修订);指出同事所写PPT中乱...

HellerZhang
37分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部