最简实例说明wait、notify、notifyAll的使用方法
/**
* 转载请注明作者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线程;
- public class NotifyTest {
- private String flag = "true";
- class NotifyThread extends Thread{
- public NotifyThread(String name) {
- super(name);
- }
- public void run() {
- try {
- sleep(3000);//推迟3秒钟通知
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- flag = "false";
- flag.notify();
- }
- };
- class WaitThread extends Thread {
- public WaitThread(String name) {
- super(name);
- }
- public void run() {
- while (flag!="false") {
- System.out.println(getName() + " begin waiting!");
- long waitTime = System.currentTimeMillis();
- try {
- flag.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- waitTime = System.currentTimeMillis() - waitTime;
- System.out.println("wait time :"+waitTime);
- }
- System.out.println(getName() + " end waiting!");
- }
- }
- public static void main(String[] args) throws InterruptedException {
- System.out.println("Main Thread Run!");
- NotifyTest test = new NotifyTest();
- NotifyThread notifyThread =test.new NotifyThread("notify01");
- WaitThread waitThread01 = test.new WaitThread("waiter01");
- WaitThread waitThread02 = test.new WaitThread("waiter02");
- WaitThread waitThread03 = test.new WaitThread("waiter03");
- notifyThread.start();
- waitThread01.start();
- waitThread02.start();
- waitThread03.start();
- }
- }
OK,如果你拿这段程序去运行下的话, 会发现根本运行不了,what happened?满屏的java.lang.IllegalMonitorStateException。
没错,这段程序有很多问题,我们一个个来看。
首先,这儿要非常注意的几个事实是
- 任何一个时刻,对象的控制权(monitor)只能被一个线程拥有。
- 无论是执行对象的wait、notify还是notifyAll方法,必须保证当前运行的线程取得了该对象的控制权(monitor)
- 如果在没有控制权的线程里执行对象的以上三种方法,就会报java.lang.IllegalMonitorStateException异常。
- JVM基于多线程,默认情况下不能保证运行时线程的时序性
基于以上几点事实,我们需要确保让线程拥有对象的控制权。
也就是说在waitThread中执行wait方法时,要保证waitThread对flag有控制权;
在notifyThread中执行notify方法时,要保证notifyThread对flag有控制权。
线程取得控制权的方法有三:
- 执行对象的某个同步实例方法。
- 执行对象对应类的同步静态方法。
- 执行对该对象加同步锁的同步块。
- synchronized (flag) {
- flag = "false";
- flag.notify();
- }
- synchronized (flag) {
- while (flag!="false") {
- System.out.println(getName() + " begin waiting!");
- long waitTime = System.currentTimeMillis();
- try {
- flag.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- waitTime = System.currentTimeMillis() - waitTime;
- System.out.println("wait time :"+waitTime);
- }
- System.out.println(getName() + " end waiting!");
- }
我们向前进了一步。
问题解决了吗?
好像运行还是报错java.lang.IllegalMonitorStateException。what happened?
这时的异常是由于在针对flag对象同步块中,更改了flag对象的状态所导致的。如下:
flag="false";
flag.notify();
对在同步块中对flag进行了赋值操作,使得flag引用的对象改变,这时候再调用notify方法时,因为没有控制权所以抛出异常。
我们可以改进一下,将flag改成一个JavaBean,然后更改它的属性不会影响到flag的引用。
我们这里改成数组来试试,也可以达到同样的效果:
- private String flag[] = {"true"};
- synchronized (flag) {
- flag[0] = "false";
- flag.notify();
- }
- synchronized (flag) {
- while (flag[0]!="false") {
- System.out.println(getName() + " begin waiting!");
- long waitTime = System.currentTimeMillis();
- try {
- flag.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
这时候再运行,不再报异常,但是线程没有结束是吧,没错,还有线程堵塞,处于wait状态。
原因很简单,我们有三个wait线程,只有一个notify线程,notify线程运行notify方法的时候,是随机通知一个正在等待的线程,所以,现在应该还有两个线程在waiting。
我们只需要将NotifyThread线程类中的flag.notify()方法改成notifyAll()就可以了。notifyAll方法会通知所有正在等待对象控制权的线程。
最终完成版如下:
- public class NotifyTest {
- private String flag[] = { "true" };
- class NotifyThread extends Thread {
- public NotifyThread(String name) {
- super(name);
- }
- public void run() {
- try {
- sleep(3000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- synchronized (flag) {
- flag[0] = "false";
- flag.notifyAll();
- }
- }
- };
- class WaitThread extends Thread {
- public WaitThread(String name) {
- super(name);
- }
- public void run() {
- synchronized (flag) {
- while (flag[0] != "false") {
- System.out.println(getName() + " begin waiting!");
- long waitTime = System.currentTimeMillis();
- try {
- flag.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- waitTime = System.currentTimeMillis() - waitTime;
- System.out.println("wait time :" + waitTime);
- }
- System.out.println(getName() + " end waiting!");
- }
- }
- }
- public static void main(String[] args) throws InterruptedException {
- System.out.println("Main Thread Run!");
- NotifyTest test = new NotifyTest();
- NotifyThread notifyThread = test.new NotifyThread("notify01");
- WaitThread waitThread01 = test.new WaitThread("waiter01");
- WaitThread waitThread02 = test.new WaitThread("waiter02");
- WaitThread waitThread03 = test.new WaitThread("waiter03");
- notifyThread.start();
- waitThread01.start();
- waitThread02.start();
- waitThread03.start();
- }
- }
最简实例说明wait、notify、notifyAll的使用方法相关推荐
- wait,notify,notifyAll作用、方法
1.阻塞阶段 线程调用wait()方法进入阻塞阶段,前提是获得monitor锁才可以(object的wait(),notify(),notifyAll()都需要先获得锁,不然会抛出异常). 2.直到以 ...
- Adapter中notify(),notifyAll(),notifyDataSetChanged(),notifyDataSetInvalidaded()方法的区别
1.notify()与notifyAll() notify()和notifyAll()一般用于唤醒被锁或等待中的adapter,两者都是object对象用于通知处在等待该对象的线程方法.notify唤 ...
- Java多线程之wait(),notify(),notifyAll()
在多线程的情况下,因为同一进程的多个线程共享同一片存储空间,在带来方便的同一时候,也带来了訪问冲突这个严重的问题.Java语言提供了专门机制以解决这样的冲突,有效避免了同一个数据对象被多个线程同一时候 ...
- JAVA线程间协作:wait.notify.notifyAll
欢迎支持笔者新作:<深入理解Kafka:核心设计与实践原理>和<RabbitMQ实战指南>,同时欢迎关注笔者的微信公众号:朱小厮的博客. 欢迎跳转到本文的原文链接:https: ...
- java并发编程(十)使用wait/notify/notifyAll实现线程间通信
转载请注明出处:http://blog.csdn.net/ns_code/article/details/17225469 wait()方法:public final void wait() thr ...
- wait, notify, notifyAll
生产者消费者问题中,我们需要共享资源时使用这些方法来使线程同步.生产者消费者例子详见:synchronized实现互斥 每个Objec(对象或实例)都有一个隐式锁.wait, notify, noti ...
- java线程的生命周期及wait(),notify(),notifyAll()的详解分析
1.java线程的生命周期 线程是一个动态执行的过程,它也有一个从产生到死亡的过程. (1)生命周期的五种状态 新建(new Thread) 当创建Thread类的一个实例(对象)时, ...
- 终于搞懂了sleep/wait/notify/notifyAll
作者:acupt,专注Java,架构师社区合伙人! sleep/wait/notify/notifyAll分别有什么作用?它们的区别是什么?wait时为什么要放在循环里而不能直接用if? 简介 首先对 ...
- [转]java 为什么wait(),notify(),notifyAll()必须在同步方法/代码块中调用?
在 Java中,所有对象都能够被作为"监视器monitor"--指一个拥有一个独占锁,一个入口队列和一个等待队列的实体entity. 所有对象的非同步 方法都能够在任意时刻被任意线 ...
- sleep() wait() notify/notifyAll() 的区别
看了一下线程这方面的知识,也结合了一些 面试的题 总结如下: 一些基础的就不说了,主要说一下这里面的几个方法,也是object的通用方法. sleep() wait() notify/ ...
最新文章
- servlet 校验密码
- js方式调用php_javascript调用PHP和PHP调用javascript的方法
- power-bi_在Power BI中的VertiPaq内-压缩成功!
- Java BIO、NIO、AIO的区别
- 您的框架有多可扩展性?
- 美国Palmbeach大学服务器整合改造案例
- linux下shell程序(一)
- HDU - 4704(费马小定理和快速幂)
- 简单Git入门本地仓库同步到远程GitHub仓库
- 基于51单片机的智能大棚浇花系统设计 花盆浇水灌溉补光散热方案原理图程序
- 打造一张万能Windows安装盘(转)
- 使用CSS3实现圆形进度条
- 《Flex+PHP RIA应用开发实战详解-梁文新版》学习日记1
- 又一巨头从Java迁移到Kotlin:关键应用全部开始切换、安卓代码库超过千万行Kotlin代码
- wangEditor在IE中截图上传问题(一)
- 微软专家教你,如何搞定树莓派 AI 服务开发
- win10常见问题,优化,软件推荐
- 易基因|一种全新的检测DNA羟甲基化的技术:ACE-Seq
- 封神台--第二章:遇到阻难!绕过WAF过滤!解题思路
- python的name属性_Python中__name__属性的妙用