/**

*  转载请注明作者longdick    http://longdick.iteye.com

*

*/

wait()、notify()、notifyAll()是三个定义在Object类里的方法,可以用来控制线程的状态。

这三个方法最终调用的都是jvm级的native方法。随着jvm运行平台的不同可能有些许差异。

  • 如果对象调用了wait方法就会使持有该对象的线程把该对象的控制权交出去,然后处于等待状态。
  • 如果对象调用了notify方法就会通知某个正在等待这个对象的控制权的线程可以继续运行。
  • 如果对象调用了notifyAll方法就会通知所有等待这个对象控制权的线程继续运行。

其中wait方法有三个over load方法:

wait()

wait(long)

wait(long,int)

wait方法通过参数可以指定等待的时长。如果没有指定参数,默认一直等待直到被通知。

以下是一个演示代码,以最简洁的方式说明复杂的问题:

简要说明下:

NotifyThread是用来模拟3秒钟后通知其他等待状态的线程的线程类;

WaitThread是用来模拟等待的线程类;

等待的中间对象是flag,一个String对象;

main方法中同时启动一个Notify线程和三个wait线程;

Java代码  
  1. public class NotifyTest {
  2. private  String flag = "true";
  3. class NotifyThread extends Thread{
  4. public NotifyThread(String name) {
  5. super(name);
  6. }
  7. public void run() {
  8. try {
  9. sleep(3000);//推迟3秒钟通知
  10. } catch (InterruptedException e) {
  11. e.printStackTrace();
  12. }
  13. flag = "false";
  14. flag.notify();
  15. }
  16. };
  17. class WaitThread extends Thread {
  18. public WaitThread(String name) {
  19. super(name);
  20. }
  21. public void run() {
  22. while (flag!="false") {
  23. System.out.println(getName() + " begin waiting!");
  24. long waitTime = System.currentTimeMillis();
  25. try {
  26. flag.wait();
  27. } catch (InterruptedException e) {
  28. e.printStackTrace();
  29. }
  30. waitTime = System.currentTimeMillis() - waitTime;
  31. System.out.println("wait time :"+waitTime);
  32. }
  33. System.out.println(getName() + " end waiting!");
  34. }
  35. }
  36. public static void main(String[] args) throws InterruptedException {
  37. System.out.println("Main Thread Run!");
  38. NotifyTest test = new NotifyTest();
  39. NotifyThread notifyThread =test.new NotifyThread("notify01");
  40. WaitThread waitThread01 = test.new WaitThread("waiter01");
  41. WaitThread waitThread02 = test.new WaitThread("waiter02");
  42. WaitThread waitThread03 = test.new WaitThread("waiter03");
  43. notifyThread.start();
  44. waitThread01.start();
  45. waitThread02.start();
  46. waitThread03.start();
  47. }
  48. }

OK,如果你拿这段程序去运行下的话, 会发现根本运行不了,what happened?满屏的java.lang.IllegalMonitorStateException。

没错,这段程序有很多问题,我们一个个来看。

首先,这儿要非常注意的几个事实是

  1. 任何一个时刻,对象的控制权(monitor)只能被一个线程拥有。
  2. 无论是执行对象的wait、notify还是notifyAll方法,必须保证当前运行的线程取得了该对象的控制权(monitor)
  3. 如果在没有控制权的线程里执行对象的以上三种方法,就会报java.lang.IllegalMonitorStateException异常。
  4. JVM基于多线程,默认情况下不能保证运行时线程的时序性

基于以上几点事实,我们需要确保让线程拥有对象的控制权。

也就是说在waitThread中执行wait方法时,要保证waitThread对flag有控制权;

在notifyThread中执行notify方法时,要保证notifyThread对flag有控制权。

线程取得控制权的方法有三:

  1. 执行对象的某个同步实例方法。
  2. 执行对象对应类的同步静态方法。
  3. 执行对该对象加同步锁的同步块。
我们用第三种方法来做说明:
将以上notify和wait方法包在同步块中
Java代码  
  1. synchronized (flag) {
  2. flag = "false";
  3. flag.notify();
  4. }
Java代码  
  1. synchronized (flag) {
  2. while (flag!="false") {
  3. System.out.println(getName() + " begin waiting!");
  4. long waitTime = System.currentTimeMillis();
  5. try {
  6. flag.wait();
  7. } catch (InterruptedException e) {
  8. e.printStackTrace();
  9. }
  10. waitTime = System.currentTimeMillis() - waitTime;
  11. System.out.println("wait time :"+waitTime);
  12. }
  13. System.out.println(getName() + " end waiting!");
  14. }

我们向前进了一步。

问题解决了吗?

好像运行还是报错java.lang.IllegalMonitorStateException。what happened?

这时的异常是由于在针对flag对象同步块中,更改了flag对象的状态所导致的。如下:

flag="false";

flag.notify();

对在同步块中对flag进行了赋值操作,使得flag引用的对象改变,这时候再调用notify方法时,因为没有控制权所以抛出异常。

我们可以改进一下,将flag改成一个JavaBean,然后更改它的属性不会影响到flag的引用。

我们这里改成数组来试试,也可以达到同样的效果:

Java代码  
  1. private   String flag[] = {"true"};
Java代码  
  1. synchronized (flag) {
  2. flag[0] = "false";
  3. flag.notify();
  4. }
Java代码  
  1. synchronized (flag) {
  2. while (flag[0]!="false") {
  3. System.out.println(getName() + " begin waiting!");
  4. long waitTime = System.currentTimeMillis();
  5. try {
  6. flag.wait();
  7. } catch (InterruptedException e) {
  8. e.printStackTrace();
  9. }

这时候再运行,不再报异常,但是线程没有结束是吧,没错,还有线程堵塞,处于wait状态。

原因很简单,我们有三个wait线程,只有一个notify线程,notify线程运行notify方法的时候,是随机通知一个正在等待的线程,所以,现在应该还有两个线程在waiting。

我们只需要将NotifyThread线程类中的flag.notify()方法改成notifyAll()就可以了。notifyAll方法会通知所有正在等待对象控制权的线程。

最终完成版如下:

Java代码  
  1. public class NotifyTest {
  2. private String flag[] = { "true" };
  3. class NotifyThread extends Thread {
  4. public NotifyThread(String name) {
  5. super(name);
  6. }
  7. public void run() {
  8. try {
  9. sleep(3000);
  10. } catch (InterruptedException e) {
  11. e.printStackTrace();
  12. }
  13. synchronized (flag) {
  14. flag[0] = "false";
  15. flag.notifyAll();
  16. }
  17. }
  18. };
  19. class WaitThread extends Thread {
  20. public WaitThread(String name) {
  21. super(name);
  22. }
  23. public void run() {
  24. synchronized (flag) {
  25. while (flag[0] != "false") {
  26. System.out.println(getName() + " begin waiting!");
  27. long waitTime = System.currentTimeMillis();
  28. try {
  29. flag.wait();
  30. } catch (InterruptedException e) {
  31. e.printStackTrace();
  32. }
  33. waitTime = System.currentTimeMillis() - waitTime;
  34. System.out.println("wait time :" + waitTime);
  35. }
  36. System.out.println(getName() + " end waiting!");
  37. }
  38. }
  39. }
  40. public static void main(String[] args) throws InterruptedException {
  41. System.out.println("Main Thread Run!");
  42. NotifyTest test = new NotifyTest();
  43. NotifyThread notifyThread = test.new NotifyThread("notify01");
  44. WaitThread waitThread01 = test.new WaitThread("waiter01");
  45. WaitThread waitThread02 = test.new WaitThread("waiter02");
  46. WaitThread waitThread03 = test.new WaitThread("waiter03");
  47. notifyThread.start();
  48. waitThread01.start();
  49. waitThread02.start();
  50. waitThread03.start();
  51. }
  52. }
from: http://longdick.iteye.com/blog/453615

最简实例说明wait、notify、notifyAll的使用方法相关推荐

  1. wait,notify,notifyAll作用、方法

    1.阻塞阶段 线程调用wait()方法进入阻塞阶段,前提是获得monitor锁才可以(object的wait(),notify(),notifyAll()都需要先获得锁,不然会抛出异常). 2.直到以 ...

  2. Adapter中notify(),notifyAll(),notifyDataSetChanged(),notifyDataSetInvalidaded()方法的区别

    1.notify()与notifyAll() notify()和notifyAll()一般用于唤醒被锁或等待中的adapter,两者都是object对象用于通知处在等待该对象的线程方法.notify唤 ...

  3. Java多线程之wait(),notify(),notifyAll()

    在多线程的情况下,因为同一进程的多个线程共享同一片存储空间,在带来方便的同一时候,也带来了訪问冲突这个严重的问题.Java语言提供了专门机制以解决这样的冲突,有效避免了同一个数据对象被多个线程同一时候 ...

  4. JAVA线程间协作:wait.notify.notifyAll

    欢迎支持笔者新作:<深入理解Kafka:核心设计与实践原理>和<RabbitMQ实战指南>,同时欢迎关注笔者的微信公众号:朱小厮的博客. 欢迎跳转到本文的原文链接:https: ...

  5. java并发编程(十)使用wait/notify/notifyAll实现线程间通信

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/17225469 wait()方法:public final void wait()  thr ...

  6. wait, notify, notifyAll

    生产者消费者问题中,我们需要共享资源时使用这些方法来使线程同步.生产者消费者例子详见:synchronized实现互斥 每个Objec(对象或实例)都有一个隐式锁.wait, notify, noti ...

  7. java线程的生命周期及wait(),notify(),notifyAll()的详解分析

    1.java线程的生命周期     线程是一个动态执行的过程,它也有一个从产生到死亡的过程. (1)生命周期的五种状态 新建(new Thread)     当创建Thread类的一个实例(对象)时, ...

  8. 终于搞懂了sleep/wait/notify/notifyAll

    作者:acupt,专注Java,架构师社区合伙人! sleep/wait/notify/notifyAll分别有什么作用?它们的区别是什么?wait时为什么要放在循环里而不能直接用if? 简介 首先对 ...

  9. [转]java 为什么wait(),notify(),notifyAll()必须在同步方法/代码块中调用?

    在 Java中,所有对象都能够被作为"监视器monitor"--指一个拥有一个独占锁,一个入口队列和一个等待队列的实体entity. 所有对象的非同步 方法都能够在任意时刻被任意线 ...

  10. sleep() wait() notify/notifyAll() 的区别

    看了一下线程这方面的知识,也结合了一些 面试的题 总结如下: 一些基础的就不说了,主要说一下这里面的几个方法,也是object的通用方法. sleep()     wait()     notify/ ...

最新文章

  1. servlet 校验密码
  2. js方式调用php_javascript调用PHP和PHP调用javascript的方法
  3. power-bi_在Power BI中的VertiPaq内-压缩成功!
  4. Java BIO、NIO、AIO的区别
  5. 您的框架有多可扩展性?
  6. 美国Palmbeach大学服务器整合改造案例
  7. linux下shell程序(一)
  8. HDU - 4704(费马小定理和快速幂)
  9. 简单Git入门本地仓库同步到远程GitHub仓库
  10. 基于51单片机的智能大棚浇花系统设计 花盆浇水灌溉补光散热方案原理图程序
  11. 打造一张万能Windows安装盘(转)
  12. 使用CSS3实现圆形进度条
  13. 《Flex+PHP RIA应用开发实战详解-梁文新版》学习日记1
  14. 又一巨头从Java迁移到Kotlin:关键应用全部开始切换、安卓代码库超过千万行Kotlin代码
  15. wangEditor在IE中截图上传问题(一)
  16. 微软专家教你,如何搞定树莓派 AI 服务开发
  17. win10常见问题,优化,软件推荐
  18. 易基因|一种全新的检测DNA羟甲基化的技术:ACE-Seq
  19. 封神台--第二章:遇到阻难!绕过WAF过滤!解题思路
  20. python的name属性_Python中__name__属性的妙用

热门文章

  1. mina 之IoService(翻译)
  2. 【SQL】SQL(基础查询)、SQL(关联查询)
  3. JS中map()与forEach()的用法
  4. 小米宋强:生态化大数据平台的深度应用实践
  5. 互联网到了什么程度?
  6. mysql 多表联查的效率_Mysql 多表联合查询效率分析
  7. Redis进阶-5.x 单节点 及Redis Cluster 3主3从集群部署
  8. 爬虫学习笔记(二十三)—— Appium+Mitmproxy
  9. Java实现List中某个对象属性中的字符串参数首字母进行排序
  10. 根据redis自增生成全局唯一订单id