Java Thread wait、notify与notifyAll
Java的Object类包含了三个final方法,允许线程就资源的锁定状态进行通信。这三个方法分别是:wait(),notify(),notifyAll(),今天来了解一下这三个方法。在任何对象上调用这些方法的当前线程应具有对象监视器(锁住了一个对象,就是获得对象相关联的监视器),否则会抛出java.lang.IllegalMonitorStateException异常。
wait
Object.wait有三种重载的实现,一个无限期等待任何其他线程地调用对象的notify或notifyAll方法来唤醒当前线程。 其他两个会使当前线程在等待特定的时间后进行唤醒。
wait()
使得当前线程进程等待,直到另一个线程在这个对象上调用了notify()方法或者notifyAll()方法。这个方法的行为,完全等价于调用wait(0),可以看它的实现代码为:
public final void wait() throws InterruptedException {
wait(0);
}
当前的线程必须获得这个对象的监视器。线程释放了监视器的所有权,直到另一个线程调用notify方法或者notifyAll方法,去唤醒在这个对象监视器上等待的其他线程。释放了监视器的所有权后,线程便进行等待,直到重新获得监视器的所有权并恢复执行。处于wait状态中的线程,可能被中断或虚假唤醒,所以这个方法应该总是在一个循环中使用:
synchronized (obj) {
while (<condition does not hold>)
obj.wait();
... // Perform action appropriate to condition
}
虚假唤醒指的是一些obj.wait()会在除了obj.notify()和obj.notifyAll()的其他情况被唤醒,而此时是不应该唤醒的,更详细的可以看Spurious_wakeup。
方法会抛出两种异常:
IllegalMonitorStateException:如果当前线程没有获得当前对象的监视器。
InterruptedException:如果某个线程在当前线程等待通知的时候,或是在等待通知之前中断了当前线程,当抛出这个异常时,当前线程的中断状态被清除。
wait(long timeout)
该方法会使得当前进程进入wait状态直到另一个线程调用notify/notifyAll,或是经过了指定的时间,线程将被唤醒。该方法会抛出异常:
IllegalArgumentException:如果timeout是负数。
wait(long timeout, int nanos)
同样的,该方法会使得当前进程进入wait状态直到另一个线程调用notify/notifyAll。它可以更加精细地控制等待的时间,以纳秒为单位测量的实时量由下式给出:1000000*timeout+nanos。除此之外,这个方法与wait(long)做相同的事情,特别的,wait(0,0)等价于wait(0)。除了其余两个wait方法会抛出的异常外,这个方法会抛出异常:
IllegalArgumentException:如果timeout是负数,或者nanos的范围不在0-999999之间时,抛出该异常。
notify
notify方法只唤醒等待对象的一个线程,并且该线程开始执行。所以如果有多个线程在等待一个对象,这个方法只会唤醒其中的一个。线程的选择取决于线程管理的OS实现。
notifyAll
notifyAll方法唤醒等待对象的所有线程,但哪一个将首先处理取决于操作系统的实现。
这些方法可用于实现生产者消费者问题,其中消费者线程正在等待队列中的对象,生产者线程将对象放入队列中并通知等待的线程。下面是一个多个线程工作在同一个对象上的例子,使用了wait,notify,notifyAll方法:
一个例子
Message :被通知唤醒的对象
public class Message {
private String msg;
public Message(String str){
this.msg=str;
}
public String getMsg() {
return msg;
}
public void setMsg(String str) {
this.msg=str;
}
}
Notifier:执行唤醒操作
public class Notifier implements Runnable {
private Message msg;
public Notifier(Message msg) {
this.msg = msg;
}
@Override
public void run() {
String name = Thread.currentThread().getName();
System.out.println(name+" started");
try {
Thread.sleep(1000);
synchronized (msg) {
msg.setMsg(name+" Notifier work done");
msg.notify();
// msg.notifyAll();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Waiter: 使Message 对象进行wait状态
public class Waiter implements Runnable{
private Message msg;
public Waiter(Message m){
this.msg=m;
}
@Override
public void run() {
String name = Thread.currentThread().getName();
synchronized (msg) {
try{
System.out.println(name+" waiting to get notified at time:"+System.currentTimeMillis());
msg.wait();
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(name+" waiter thread got notified at time:"+System.currentTimeMillis());
//process the message now
System.out.println(name+" processed: "+msg.getMsg());
}
}
}
WaitNotifyTest:测试
public class WaitNotifyTest {
public static void main(String[] args) {
Message msg = new Message("process it");
Waiter waiter = new Waiter(msg);
new Thread(waiter,"waiter").start();
Waiter waiter1 = new Waiter(msg);
new Thread(waiter1, "waiter1").start();
Notifier notifier = new Notifier(msg);
new Thread(notifier, "notifier").start();
System.out.println("All the threads are started");
}
}
输出:
waiter waiting to get notified at time:1516757290631
All the threads are started
waiter1 waiting to get notified at time:1516757290632
notifier started
waiter waiter thread got notified at time:1516757291632
waiter processed: notifier Notifier work done
可以看到两个线程在对象msg上进行等待,调用notify方法时,只有一个线程被唤醒,此时程序并没有退出,因为还有一个线程在等待。
如果把notify方法改成notifyAll,运行结果为:
waiter waiting to get notified at time:1516757437164
waiter1 waiting to get notified at time:1516757437164
All the threads are started
notifier started
waiter1 waiter thread got notified at time:1516757438165
waiter1 processed: notifier Notifier work done
waiter waiter thread got notified at time:1516757438165
waiter processed: notifier Notifier work done
可以看到两个线程都被唤醒了,程序也退出运行了。
(完)
Java Thread wait、notify与notifyAll的更多相关文章
- Java Thread wait, notify and notifyAll Example
Java Thread wait, notify and notifyAll Example Java线程中的使用的wait,notify和nitifyAll方法示例. The Object clas ...
- [译]Java Thread wait, notify和notifyAll示例
Java Thread wait, notify和notifyAll示例 Java上的Object类定义了三个final方法用于不同线程间关于某资源上的锁状态交互,这三个方法是:wait(), not ...
- java wait()和notify()、notifyAll()
图见<JAVA并发编程的艺术>P98-101 这三个方法都是java.lang.Object的方法,用于协调多个线程对共享数据的存取,必须在synchronized语句块中使用!这三个方法 ...
- Java的wait(), notify()和notifyAll()使用小结
wait(),notify()和notifyAll()都是java.lang.Object的方法: wait(): Causes the current thread to wait until an ...
- Java多线程 wait, notify 和 notifyAll
Java的Object类 public class Object { public final native void notify(); public final native void notif ...
- Java的wait(), notify()和notifyAll()使用心得(转)
本篇文章是对java的 wait(),notify(),notifyAll()进行了详细的分析介绍,需要的朋友参考下wait(),notify()和notifyAll()都是java.lang.Obj ...
- java中的notify和notifyAll有什么区别?
先说两个概念:锁池和等待池 锁池:假设线程A已经拥有了某个对象(注意:不是类)的锁,而其它的线程想要调用这个对象的某个synchronized方法(或者synchronized块),由于这些线程在进入 ...
- 精通java并发-wait,notify和notifyAll的总结(含案例)
目前CSDN,博客园,简书同步发表中,更多精彩欢迎访问我的gitee pages wait,notify和notifyAll 总结 在调用wait方法时,线程必须要持有被调用对象的锁,当调用wait方 ...
- Java 中 wait, notify 和 notifyAll的正确使用 – 以生产者消费者模型为例
如何使用Wait 尽管关于wait和notify的概念很基础,它们也都是Object类的函数,但用它们来写代码却并不简单.如果你在面试中让应聘者来手写代码,用wait和notify解决生产者消费者问题 ...
- Java 多线程学习笔记:wait、notify、notifyAll的阻塞和恢复
前言:昨天尝试用Java自行实现生产者消费者问题(Producer-Consumer Problem),在coding时,使用到了Condition的await和signalAll方法,然后顺便想起了 ...
随机推荐
- vbs的一些入门基础。。。
VBS(VBScript的进一步简写)是基于Visual Basic的脚本语言. Microsoft Visual Basic是微软公司出品的一套可视化编程工具, 语法基于Basic. 脚本语言, 就 ...
- Neo4j学习笔记(1)——使用API编写一个Hello World程序
项目的创建及配置 因为Neo4j依赖的jar包比较多,所以推荐使用Maven来管理. 首先创建一个Maven Project,添加依赖: <dependency> <groupId& ...
- 安装lamp代码
tar -zxvf mysqladdUser mysql -s /sbin/nologinmv mysql /usr/local/mysql (改目录下直接存储bin docs等目录)mkdir -p ...
- C/C++调用Golang 一
C/C++调用Golang 一 (开发环境: 操作系统: windows 7 32位操作系统 C++: visual studio 2010 Golang:go version go1.9 windo ...
- Linux发行版 CentOS6.5下删除分区操作
本文地址http://comexchan.cnblogs.com/,作者Comex Chan,尊重知识产权,转载请注明出处,谢谢! 有时候,发现分区分错了.需要删除分区,只需按照分区的步骤逆向操作 ...
- 使用line-height来垂直居中在安卓设备并不居中,利用ji调整
先判断智能机浏览器的版本信息:方法有两种,但是第一种兼容性更好,但是使用了device插件 第一种: if (device.android()){ } 第二种: var ua = navigator. ...
- 麻瓜之我要学sql,啦啦啦啦
四张表 学生表:编号,姓名,性别,班级,生日 CREATE TABLE IF NOT EXISTS student( sno TINYINT UNSIGNED NOT NULL, sname ) NO ...
- Django_调查问卷
1.问卷的保存按钮 前端通过ajax把数据发过来后端处理数据,然后返回给前端2.对问卷做答 首先用户进行登录,验证 条件:1.只有本班的学生才能对问卷做答 2.已经参加过的不能再次访问 ...
- VIM常见用法总结
欢迎和大家交流技术相关问题: 邮箱: jiangxinnju@163.com 博客园地址: http://www.cnblogs.com/jiangxinnju GitHub地址: https://g ...
- Head First设计模式之备忘录模式
一.定义 不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态.这样就可以将该对象恢复到原先保存的状态 二.结构 备忘录模式中主要有三类角色: 发起人角色:记录当前时刻的内部状态, ...