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的更多相关文章

  1. Java Thread wait, notify and notifyAll Example

    Java Thread wait, notify and notifyAll Example Java线程中的使用的wait,notify和nitifyAll方法示例. The Object clas ...

  2. [译]Java Thread wait, notify和notifyAll示例

    Java Thread wait, notify和notifyAll示例 Java上的Object类定义了三个final方法用于不同线程间关于某资源上的锁状态交互,这三个方法是:wait(), not ...

  3. java wait()和notify()、notifyAll()

    图见<JAVA并发编程的艺术>P98-101 这三个方法都是java.lang.Object的方法,用于协调多个线程对共享数据的存取,必须在synchronized语句块中使用!这三个方法 ...

  4. Java的wait(), notify()和notifyAll()使用小结

    wait(),notify()和notifyAll()都是java.lang.Object的方法: wait(): Causes the current thread to wait until an ...

  5. Java多线程 wait, notify 和 notifyAll

    Java的Object类 public class Object { public final native void notify(); public final native void notif ...

  6. Java的wait(), notify()和notifyAll()使用心得(转)

    本篇文章是对java的 wait(),notify(),notifyAll()进行了详细的分析介绍,需要的朋友参考下wait(),notify()和notifyAll()都是java.lang.Obj ...

  7. java中的notify和notifyAll有什么区别?

    先说两个概念:锁池和等待池 锁池:假设线程A已经拥有了某个对象(注意:不是类)的锁,而其它的线程想要调用这个对象的某个synchronized方法(或者synchronized块),由于这些线程在进入 ...

  8. 精通java并发-wait,notify和notifyAll的总结(含案例)

    目前CSDN,博客园,简书同步发表中,更多精彩欢迎访问我的gitee pages wait,notify和notifyAll 总结 在调用wait方法时,线程必须要持有被调用对象的锁,当调用wait方 ...

  9. Java 中 wait, notify 和 notifyAll的正确使用 – 以生产者消费者模型为例

    如何使用Wait 尽管关于wait和notify的概念很基础,它们也都是Object类的函数,但用它们来写代码却并不简单.如果你在面试中让应聘者来手写代码,用wait和notify解决生产者消费者问题 ...

  10. Java 多线程学习笔记:wait、notify、notifyAll的阻塞和恢复

    前言:昨天尝试用Java自行实现生产者消费者问题(Producer-Consumer Problem),在coding时,使用到了Condition的await和signalAll方法,然后顺便想起了 ...

随机推荐

  1. jquery $.fn $.fx是什么意思有什么用

    $.fn是指jquery的命名空间,加上fn上的方法及属性,会对jquery实例每一个有效, .fn是指jquery的命名空间,加上fn上的方法及属性,会对jquery实例每一个有效. 如扩展$.fn ...

  2. 多线程下QAxObject指针为NULL的解决办法

    项目中需要对Excel进行操作,把数据中的数据写入到Excel文件中.在数据量大的情况下,操作Excel是一件费时的操作. 但是执行到下列代码时就会出现空指针的情况: QAxObject *excel ...

  3. Struts2-整理笔记(四)Action生命周期、如何获取参数(3种)、集合类型参数封装

    一.Action生命周期 每次请求到来时,都会创建一个新的Action实例 Action是线程安全的,可以使用成员变量接收参数 二.获取参数的方式(3种) 1.属性驱动获得参数 每次请求Action时 ...

  4. Generation Axe 吉他之夜音乐会-广州站 感受

    本人第一次看音乐会,演唱会跟音乐会是有区别的哈,演唱会以表演.舞蹈.歌唱为主,还有很多特别嘉宾 演出时间: 从20点开始一直到23点多才结束,有五个吉他手,开场跟结束五个吉他手一齐演出.平均每个人表演 ...

  5. HBase跨地区机房的压测小程序——从开发到打包部署(图文版)

    今天做了一个跨地区机房的压测小程序,主要的思路就是基于事先准备好的rowkey文件,利用多线程模拟并发的rowkey查询,可以实现并发数的自由控制.主要是整个流程下来,遇到了点打包的坑,所以特意记录下 ...

  6. Ajax异步提交登录(2)--登录使用

    http://cjp1989.iteye.com/blog/1740964 1.Ajax的原理: Ajax的原理就是:通过javascript的方式,将前台数据通过xmlhttp对象传递到后台,后台在 ...

  7. Pyhon学习_04_字典、集合

    字典.集合两种基本类型都是通过映射的方式访问. 字典 python中的字典和perl中的哈希是很相似的,包括其重要的几条属性: 1. 键值必须是唯一的 2. 键值必须是可哈希的,也就是键值不能够是可变 ...

  8. 前端学习_01_css网页布局

    引子 之前也自己陆陆续续地学了一些web方面的知识,包括前段和后端都有涉及到,自己也比较感兴趣,感谢peter老师,愿意无偿提供从零开始的教学,之前也看过peter老师的一些视频,节奏非常适合我,决心 ...

  9. Nginx优化use参数epoll,kqueue,rtsig,eventport,poll

    转自:http://blog.sina.com.cn/s/blog_5eaf88f10100gkrq.html Nginx use参数分析对比 下图对比了poll select epoll和kqueu ...

  10. 【Bootstrap简单用法】

    一.下载及使用 参考网站:http://www.bootcss.com/ 1.使用 BootCDN 提供的免费 CDN 加速服务(同时支持 http 和 https 协议) <!-- 最新版本的 ...