wait、notify、notifyAll的阻塞和恢复
前言:昨天尝试用Java自行实现生产者消费者问题(Producer-Consumer Problem),在coding时,使用到了Condition的await和signalAll方法,然后顺便想起了wait和notify,在开发中遇到了一个问题:wait、notify等阻塞和恢复的时机分别是什么?在网上Google了很久各种博文后,发现几乎没有人提到这个点。最后在官方文档中才找到了相应的介绍。
(一)准备
按照惯例应该是要先介绍一下wait、notify和notifyAll的基础知识。我找到了一篇不错的文章:《Java的wait(), notify()和notifyAll()使用小结》,它甚至介绍了为什么wait等方法为什么必须先获得对象锁。在这里我就不重复说了。
(二)阻塞和恢复
(1)wait方法
wait方法继承自Object类(方法修饰符为fianl native,这也解释了为什么condition类中不能重写wait等方法),一共有三个方法:

public final void wait(long timeout)
throws InterruptedException public final void wait(long timeout, int nanos)
throws InterruptedException public final void wait()
throws InterruptedException

阻塞:这三个方法的调用都会使当前线程阻塞。该线程将会被放置到对该Object的请求等待队列中,然后让出当前对Object所拥有的所有的同步请求。线程会一直暂停所有线程调度,直到下面其中一种情况发生:
① 其他线程调用了该Object的notify方法,而该线程刚好是那个被唤醒的线程;
② 其他线程调用了该Object的notifyAll方法;
③ 其他对象中断/杀死了该线程;
④ (这种情况,只针对前两个方法)线程在等待指定的时间后;
恢复:线程将会从等待队列中移除,重新成为可调度线程。它会与其他线程以常规的方式竞争对象同步请求。一旦它重新获得对象的同步请求,所有之前的请求状态都会恢复,也就是线程调用wait的地方的状态。线程将会在之前调用wait的地方继续运行下去。
(2)notify和notifyAll方法
notify的作用就是唤醒请求队列中的一个线程,而notifyAll唤醒的是请求队列中的所有线程。
被唤醒的线程不会马上运行,除非获取了该Object的锁。也就是说,调用notify的线程,在调用notify后,不会像wait一样,马上阻塞线程的运行。而是继续运行,直到相应的线程调度完成或者让出Object的锁。而被唤醒的线程会在当前线程让出Object锁后,与其他线程以常规的方式竞争对象锁(正如上面提到的)。
参考资料:
https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html
public class WaitNotifyDemo {
private volatile int val = ;
private Object o1= new Object();
private Object o2= new Object();
public class PrinterA implements Runnable {
public void run() {
while (val <= ) {
synchronized (o2) {
try {
System.out.println("");
o2.wait();
System.out.println("");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public class PrinterC implements Runnable {
public void run() {
while (val <= ) {
synchronized (o2) {
try {
System.out.println("");
o2.wait();
System.out.println("");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public class PrinterB implements Runnable {
public void run() {
while (val <= ) {
synchronized (o2) {
o2.notify();
// o2.notifyAll();
}
}
}
}
public static void main(String[] args) {
WaitNotifyDemo demo = new WaitNotifyDemo();
demo.doPrint();
}
private void doPrint() {
PrinterA pa = new PrinterA();
Thread a = new Thread(pa);
a.setName("printerA");
a.start();
PrinterC pc = new PrinterC();
Thread c = new Thread(pc);
c.setName("printerC");
c.start();
PrinterB pB = new PrinterB();
Thread b = new Thread(pB);
b.setName("printerA");
b.start();
}
}
wait、notify、notifyAll的阻塞和恢复的更多相关文章
- Java 多线程学习笔记:wait、notify、notifyAll的阻塞和恢复
前言:昨天尝试用Java自行实现生产者消费者问题(Producer-Consumer Problem),在coding时,使用到了Condition的await和signalAll方法,然后顺便想起了 ...
- java 多线程之wait(),notify,notifyAll(),yield()
wait(),notify(),notifyAll()不属于Thread类,而是属于Object基础类,也就是说每个对像都有wait(),notify(),notifyAll()的功能.因为都个对像都 ...
- Java多线程8:wait()和notify()/notifyAll()
轮询 线程本身是操作系统中独立的个体,但是线程与线程之间不是独立的个体,因为它们彼此之间要相互通信和协作. 想像一个场景,A线程做int型变量i的累加操作,B线程等待i到了10000就打印出i,怎么处 ...
- Java多线程学习之wait、notify/notifyAll 详解
1.wait().notify/notifyAll() 方法是Object的本地final方法,无法被重写. 2.wait()使当前线程阻塞,前提是 必须先获得锁,一般配合synchronized 关 ...
- 【java线程系列】java线程系列之线程间的交互wait()/notify()/notifyAll()及生产者与消费者模型
关于线程,博主写过java线程详解基本上把java线程的基础知识都讲解到位了,但是那还远远不够,多线程的存在就是为了让多个线程去协作来完成某一具体任务,比如生产者与消费者模型,因此了解线程间的协作是非 ...
- Object的wait/notify/notifyAll&&Thread的sleep/yield/join/holdsLock
一.wait/notify/notifyAll都是Object类的实例方法 1.wait方法:阻塞当前线程等待notify/notifyAll方法的唤醒,或等待超时后自动唤醒. wait等待其实是对象 ...
- 使用ReentrantLock和Condition来代替内置锁和wait(),notify(),notifyAll()
使用ReentrantLock可以替代内置锁,当使用内置锁的时候,我们可以使用wait() nitify()和notifyAll()来控制线程之间的协作,那么,当我们使用ReentrantLock的时 ...
- java多线程14 :wait()和notify()/notifyAll()
轮询 线程本身是操作系统中独立的个体,但是线程与线程之间不是独立的个体,因为它们彼此之间要相互通信和协作. 想像一个场景,A线程做int型变量i的累加操作,B线程等待i到了10000就打印出i,怎么处 ...
- Java 多线程 线程的五种状态,线程 Sleep, Wait, notify, notifyAll
一.先来看看Thread类里面都有哪几种状态,在Thread.class中可以找到这个枚举,它定义了线程的相关状态: public enum State { NEW, RUNNABLE, BLOCKE ...
随机推荐
- 【Leetcode】【Medium】Palindrome Partitioning
Given a string s, partition s such that every substring of the partition is a palindrome. Return all ...
- google hack 之 查询语法
google hack 之 查询语法 文/玄魂 前言 谷歌网页搜索技术,大部分在百度等搜索引擎中也适用.同样,这些搜索技术是来源于传统数据库检索技术,因而,对这部分的学习,能为后续章节的数据库检索 ...
- Hash哈希(二)一致性Hash(C++实现)
一致性Hash 一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希(DHT)实现算法,设计目标是为了解决因特网中的热点(Hot spot)问题,经常用于分布式.负载均衡等. 原理 一致哈希是 ...
- 说不尽的MVVM(2) – MVVM初体验
知识预备 阅读本文,我假定你已经具备以下知识: C#.WPF基础知识 了解Lambda表达式和TPL 对事件驱动模型的了解 知道ICommand接口 发生了什么 某程序员接到一个需求,编写一个媒体渲染 ...
- paip.判断字符是否中文与以及判读是否是汉字uapi python java php
paip.判断字符是否中文与以及判读是否是汉字uapi python java php ##判断中文的原理 注意: 中文与汉字CJKV 的区别..日本,韩国,新加坡,古越南等国家也用汉字,但不是中 ...
- paip.输入法英文词库的处理 python 代码 o4
paip.输入法英文词库的处理 python 代码 o4 目标是eng>>>中文>>atian 当输入非atian词的时候儿,能打印出 atian pinyin > ...
- 通过MSSQl作业定时执行批处理BAT文件
前言 有些时候,我们可能会需要定时执行一下批处理来达到一定的目的,比如Oracle数据库的定时备份,当然Oracle也可以通过Rman实现定时备份.我们大多数的时候是通过操作系统的计划任务实现定时执行 ...
- eclipse安装activiti工作流插件
方式一:在有网络的情况下,安装流程设计器步骤如下: 1.点击eclipse上方工具栏的Help,选择Install New Software 2.弹出如下窗口,然后填写插件名称和安装地址 Name: ...
- Radio Basics for RFID
Radio Basics for RFID The following is excerpted from Chapter 3: Radio Basics for UHF RFID from the ...
- RabbitMQ的工作队列和路由
工作队列:Working Queue 工作队列这个概念与简单的发送/接收消息的区别就是:接收方接收到消息后,可能需要花费更长的时间来处理消息,这个过程就叫一个Work/Task. 几个概念 分 ...