java wait() notify_Java的wait(), notify()和notifyAll()使用小结
wait(),notify()和notifyAll()都是java.lang.Object的方法:
wait(): Causes the current thread to wait until another thread invokes the notify() method or the notifyAll() method for this object.
notify(): Wakes up a single thread that is waiting on this object's monitor.
notifyAll(): Wakes up all threads that are waiting on this object's monitor.
这三个方法,都是Java语言提供的实现线程间阻塞(Blocking)和控制进程内调度(inter-process communication)的底层机制。在解释如何使用前,先说明一下两点:
1. 正如Java内任何对象都能成为锁(Lock)一样,任何对象也都能成为条件队列(Condition queue)。而这个对象里的wait(), notify()和notifyAll()则是这个条件队列的固有(intrinsic)的方法。
2. 一个对象的固有锁和它的固有条件队列是相关的,为了调用对象X内条件队列的方法,你必须获得对象X的锁。这是因为等待状态条件的机制和保证状态连续性的机制是紧密的结合在一起的。
(An object's intrinsic lock and its intrinsic condition queue are related: in order to call any of the condition queue methods on object X, you must hold the lock on X. This is because the mechanism for waiting for state-based conditions is necessarily tightly bound to the mechanism fo preserving state consistency)
根据上述两点,在调用wait(), notify()或notifyAll()的时候,必须先获得锁,且状态变量须由该锁保护,而固有锁对象与固有条件队列对象又是同一个对象。也就是说,要在某个对象上执行wait,notify,先必须锁定该对象,而对应的状态变量也是由该对象锁保护的。
知道怎么使用后,我们来问下面的问题:
1. 执行wait, notify时,不获得锁会如何?
请看代码:
public static void main(String[] args) throwsInterruptedException {
Object obj = newObject();
obj.wait();
obj.notifyAll();
}
执行以上代码,会抛出java.lang.IllegalMonitorStateException的异常。
2. 执行wait, notify时,不获得该对象的锁会如何?
请看代码:
public static void main(String[] args) throwsInterruptedException {
Object obj = newObject();
Object lock = newObject();
synchronized(lock) {
obj.wait();
obj.notifyAll();
}
}
执行代码,同样会抛出java.lang.IllegalMonitorStateException的异常。
3. 为什么在执行wait, notify时,必须获得该对象的锁?
这是因为,如果没有锁,wait和notify有可能会产生竞态条件(Race Condition)。考虑以下生产者和消费者的情景:
1.1生产者检查条件(如缓存满了)-> 1.2生产者必须等待
2.1消费者消费了一个单位的缓存 -> 2.2重新设置了条件(如缓存没满) -> 2.3调用notifyAll()唤醒生产者
我们希望的顺序是: 1.1->1.2->2.1->2.2->2.3
但在多线程情况下,顺序有可能是 1.1->2.1->2.2->2.3->1.2。也就是说,在生产者还没wait之前,消费者就已经notifyAll了,这样的话,生产者会一直等下去。
所以,要解决这个问题,必须在wait和notifyAll的时候,获得该对象的锁,以保证同步。
请看以下利用wait,notify实现的一个生产者、一个消费者和一个单位的缓存的简单模型:
public classQueueBuffer {
intn;
boolean valueSet = false;
synchronized intget() {
if (!valueSet)
try{
wait();
} catch(InterruptedException e) {
System.out.println("InterruptedException caught");
}
System.out.println("Got: " +n);
valueSet = false;
notify();
returnn;
}
synchronized void put(intn) {
if(valueSet)
try{
wait();
} catch(InterruptedException e) {
System.out.println("InterruptedException caught");
}
this.n =n;
valueSet = true;
System.out.println("Put: " +n);
notify();
}
}
public class Producer implementsRunnable {
privateQueueBuffer q;
Producer(QueueBuffer q) {
this.q =q;
new Thread(this, "Producer").start();
}
public voidrun() {
int i = 0;
while (true) {
q.put(i++);
}
}
}
public class Consumer implementsRunnable {
privateQueueBuffer q;
Consumer(QueueBuffer q) {
this.q =q;
new Thread(this, "Consumer").start();
}
public voidrun() {
while (true) {
q.get();
}
}
}
public classMain {
public static voidmain(String[] args) {
QueueBuffer q = newQueueBuffer();
newProducer(q);
newConsumer(q);
System.out.println("Press Control-C to stop.");
}
}
所以,JVM通过在执行的时候抛出IllegalMonitorStateException的异常,来确保wait, notify时,获得了对象的锁,从而消除隐藏的Race Condition。
最后来看看一道题:写一个多线程程序,交替输出1,2,1,2,1,2......
利用wait, notify解决:
1 public class OutputThread implementsRunnable {
2
3 private intnum;
4 privateObject lock;
5
6 public OutputThread(intnum, Object lock) {
7 super();
8 this.num =num;
9 this.lock =lock;
10 }
11
12 public voidrun() {
13 try{
14 while(true){
15 synchronized(lock){
16 lock.notifyAll();
17 lock.wait();
18 System.out.println(num);
19 }
20 }
21 } catch(InterruptedException e) {
22 //TODO Auto-generated catch block
23 e.printStackTrace();
24 }
25
26 }
27
28 public static voidmain(String[] args){
29 final Object lock = newObject();
30
31 Thread thread1 = new Thread(new OutputThread(1,lock));
32 Thread thread2 = new Thread(new OutputThread(2, lock));
33
34 thread1.start();
35 thread2.start();
36 }
37
38 }
《Java Concurrency in Practice》里的第14章,对wait, notify有更加详细的介绍。
参考:
java wait() notify_Java的wait(), notify()和notifyAll()使用小结相关推荐
- 如何在 Java 中正确使用 wait, notify 和 notifyAll – 以生产者消费者模型为例
欢迎支持笔者新作:<深入理解Kafka:核心设计与实践原理>和<RabbitMQ实战指南>,同时欢迎关注笔者的微信公众号:朱小厮的博客. wait, notify 和 noti ...
- 第五章 Java 中的 wait、notify 和 notifyAll 方法示例
您可能已经注意到 Object 类具有三个 final 方法,分别称为 wait.notify 和 notifyAll.这些方法用于线程间通信.Java 5 引入了执行器框架,它为您处理线程间通信,并 ...
- java多线程notify_Java多线程 wait notify
源码 java public final native void notify(); public final native void notifyAll(); public final void w ...
- 如何在 Java 中正确使用 wait, notify 和 notifyAll?
简介 wait,notify,notifyAll,都是属于object对象提供的方法,但在实际工作中怎么使用这几个方法,确是很多程序员清楚,不够明白,在群里问,有人说,哪个线程想wait,就用 ...
- java多线程设计wait、notify、notifyall、synchronized的使用机制
wait.notify.notifyall.synchronized的使用机制: synchronized(obj) { while(!condition) { obj.wait(); } obj.d ...
- java中的notify和notifyAll有什么区别?
作者:知乎用户 链接:https://www.zhihu.com/question/37601861/answer/145545371 来源:知乎 著作权归作者所有.商业转载请联系作者获得授权,非商业 ...
- java 多线程 notify_Java多线程8:wait()和notify()/notifyAll()
轮询 线程本身是操作系统中独立的个体,但是线程与线程之间不是独立的个体,因为它们彼此之间要相互通信和协作. 想像一个场景,A线程做int型变量i的累加操作,B线程等待i到了10000就打印出i,怎么处 ...
- Java多线程协作(wait、notify、 notifyAll)
http://sunjun041640.blog.163.com/blog/static/25626832201041411210560/ Java监视器支持两种线程:互斥和 协作. 前面我们介绍了采 ...
- 【Java 线程的深入研究3】最简单实例说明wait、notify、notifyAll的使用方法
wait().notify().notifyAll()是三个定义在Object类里的方法,可以用来控制线程的状态. 这三个方法最终调用的都是jvm级的native方法.随着jvm运行平台的不同可能有些 ...
- 19、Java并发编程:线程间协作的两种方式:wait、notify、notifyAll和Condition
Java并发编程:线程间协作的两种方式:wait.notify.notifyAll和Condition 在前面我们将了很多关于同步的问题,然而在现实中,需要线程之间的协作.比如说最经典的生产者-消费者 ...
最新文章
- 融合AI与大数据技术,腾讯教育发布智能作业灯
- MyBatis缓存机制学习
- SpringMVC 文件上传
- leetcode894.AllPossibleFullBinaryTrees
- 刘强东事后首发声;拼多多入局 AI ;三星手机 CEO 承认危机 | 极客头条
- python一行输出_#python版一行内容分行输出
- matlab在图像处理中的应用实验,MATLAB实验Matlab在数字图像处理中的应用
- 苹果服务器消息转发,好消息!微信语音也可以转发啦!不好的消息!目前苹果还不行!...
- 计算机网络原理学习笔记
- 安装黑苹果目前最详细教程
- Source Insight 4.0.0086 Patched
- 百度实时热点词采集工具
- 《基于深度学习的加密流量识别研究》-2022毕设笔记
- DataFrame上下或左右合并 pd.concat
- dos攻击原理及攻击实例(带脚本)
- _nop_();的由来和作用
- 什么是MIL、SIL、PIL和HIL?
- android intent.action pick,android intent pick
- 日本的养老现状,会是我们的未来吗?
- 陌陌6.0核心诉求:改变看脸社交
热门文章
- video-audio
- angular2 --使用DecimalPipe格式化数字
- 在 Emacs 里修改现有文件的编码格式(转载)
- Git 常用命令(转)
- 五个Metro UI 风格的网页设计
- comsol软件_COMSOL软件 5.4 版本新增“薛定谔-泊松方程“多物理场接口
- 拓端tecdat|R语言中的划分聚类模型
- matlab 例题sin,matlab基础练习题(带答案).doc
- LeetCode3 无重复字符的最长子串
- 一步之遥 c语言答案是多少,蓝桥杯之一步之遥-Go语言中文社区