wait()、notify、notifyAll()方法

wait()、notify()、notifyAll()是三个定义在Object类里的方法,可以用来控制线程的状态。

这三个方法最终调用的都是jvm级的native方法。随着jvm运行平台的不同可能有些许差异。

  • 如果对象调用了wait方法就会使持有该对象的线程把该对象的控制权交出去,然后处于等待状态。
  • 如果对象调用了notify方法就会通知某个正在等待这个对象的控制权的线程可以继续运行。
  • 如果对象调用了notifyAll方法就会通知所有等待这个对象控制权的线程继续运行。

    注意:一定要在线程同步中使用,并且是同一个锁的资源
public class NotifyAllDemo {
private static volatile Object reA = new Object();
public static void main(String[] args) throws InterruptedException{
Thread threadA = new Thread(new Runnable() {
@Override
public void run() {
synchronized (reA){
System.out.println("threadA get reA lock");
try {
System.out.println("threadA begin wait");
reA.wait();
System.out.println("threadA end wait");
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
});
Thread threadB = new Thread(new Runnable() {
@Override
public void run() {
synchronized (reA){
System.out.println("threadB get reA lock");
try {
System.out.println("threadB begin wait");
reA.wait();
System.out.println("threadB end wait");
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
});
Thread threadC = new Thread(new Runnable() {
@Override
public void run() {
synchronized (reA){
System.out.println("threadC begin notify");
//reA.notify();
reA.notifyAll();
}
}
});
threadA.start();
threadB.start();
Thread.sleep(1000);
threadC.start();
threadA.join();
threadB.join();
threadC.join();
System.out.println("main over"); //调用notify()
//threadA get reA lock
//threadA begin wait
//threadB get reA lock
//threadB begin wait
//threadC begin notify
//threadA end wait //调用notifyAll()
//threadA get reA lock
//threadA begin wait
//threadB get reA lock
//threadB begin wait
//threadC begin notify
//threadA end wait
//threadB end wait
//main over //在线程 B 调用共享变量的 wait()方法前线程C调用了共享变量的 notifyAll 方法, 这样,只有线程 A 被唤醒,而线程 B 并没有被唤醒, 还是处于阻塞状态
}
}

补充

/**
* p56
线程T1 线程T2
取得Object监视器
Object.wait()
释放Object监视器
取得Object监视器
Object.notify()
等待Object监视器 释放Object监视器
重获Object监视器
继续执行
*
* T1在正确执行wait()方法前,首先必须获得object对象的监视器,而wait()方法在执行后,会释放这个监视器,这样做的
* 目的是使得其他等待在object对象上的线程不至于因为T1的休眠而全部无法正常执行。
* 线程T2在notify()调用前,必须获得object的监视器,T1已经释放了这个监视器,因此,T2可以顺利获得object的监视器。
* 接着,T2执行了notify()方法尝试唤醒一个等待线程,这里假设唤醒了T1,T1在被唤醒后,要做的第一件事并不是执行后续的代码,
* 而是要尝试重新获得object的监视器,而这个监视器也正是T1在wait()方法执行前所持有的那个。如果暂时无法获得,T1还必须
* 要等待这个监视器,当监视器顺利获得后,T1才可以真正意义上的继续执行。
*/
public class WaitAndNotifyDemo {
final static Object object = new Object();
public static class T1 extends Thread{
@Override
public void run() {
synchronized (object){
System.out.println(System.currentTimeMillis()+":T1 start!");
try {
System.out.println(System.currentTimeMillis()+":T1 wait for object");
object.wait();//执行后,T1会进行等待,并释放object的锁
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis()+":T1 end!");
}
}
}
public static class T2 extends Thread{
@Override
public void run() {
synchronized (object){
System.out.println(System.currentTimeMillis()+":T2 start!notify one thread");
object.notify();
System.out.println(System.currentTimeMillis()+":T2 end!");
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args){
Thread t1 = new T1();
Thread t2 = new T2();
t1.start();
t2.start();
//1566261979660:T1 start!
//1566261979660:T1 wait for object
//1566261979660:T2 start!notify one thread
//1566261979660:T2 end! //此时会卡秒,更明显地说明T1在得到notify()通知后,还是会先尝试重新获得object的对象锁
//1566261981665:T1 end! /**
* object.wait()与Thead.sleep()区别:
* wait()可以被唤醒,会释放目标对象的锁,而Thead.sleep()方法不会释放任何资源
*/
}
}
/**
* 模拟过时的挂起(suspend),继续执行(resume)
*/
public class WaitAndNotifyDemo2 {
public static Object object = new Object();
public static class ChangeObjectThead extends Thread{
volatile boolean suspendme = false;
//挂起线程
public void suspendMe(){
suspendme = true;
}
//继续执行线程
public void resumeMe(){
suspendme = false;
synchronized (this){
notify();
}
}
@Override
public void run() {
while (true){
synchronized (this){
//先检查是否被挂起,如果是,则执行wait()方法进行等待,否则进行正常的处理
while (suspendme){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
synchronized (object){
System.out.println("in ChangeObjectThread");
}
Thread.yield();
}
}
}
}
public static class ReadObjectThread extends Thread{
@Override
public void run() {
while (true){
synchronized (object){
System.out.println("in ReadObjectThread");
}
Thread.yield();
}
}
}
public static void main(String[] args) throws InterruptedException{
ChangeObjectThead t1 = new ChangeObjectThead();
ReadObjectThread t2 = new ReadObjectThread();
t1.start();
t2.start();
Thread.sleep(1000);
System.out.println("t1 suspendMe");
t1.suspendMe();
Thread.sleep(2000);
System.out.println("t1 resumeMe");
t1.resumeMe();
//in ChangeObjectThread
//in ReadObjectThread
//in ChangeObjectThread
//...
//in ReadObjectThread
//in ReadObjectThread
//in ReadObjectThread
//in ReadObjectThread
//in ReadObjectThread
//in ReadObjectThread
//...
//in ReadObjectThread
//in ChangeObjectThread
//in ReadObjectThread
//in ChangeObjectThread
//in ReadObjectThread
//in ChangeObjectThread
}
}

03.线程的通知notify与等待wait的更多相关文章

  1. 多线程-等待(Wait)和通知(notify)

    1.为了支撑多线程之间的协作,JDK提供了两个非常重要的线程接口:等待wait()方法和通知notify()方法. 这两个方法并不是在Thread类中的,而是输出在Object类.这意味着任何对象都可 ...

  2. 线程中wait/notify/notifyAll的用法

    前言 多线程时,最关注的就是线程同步,线程间的同步一般用锁来实现,常见的锁就是synchronized和lock.用了synchronized,就不得不提到wait/notify/notifyAll. ...

  3. Java并发之(2):线程通信wait/notify(TIJ_21_5)

    简介: java中线程间同步的最基本的方式就是使用wait()&notify()&notifyAll(),它们是线程间的握手机制.除了上述方法,java5还在java.util.con ...

  4. Java线程的wait(), notify()和notifyAll()

    Java线程生命周期 类java.lang.Thread包含一个静态的State enum用于定义每种可能的状态. 在任意的时间点, 线程会处于以下的状态之一: NEW – 新创建的线程, 还未启动( ...

  5. Java 线程之间的通讯,等待唤醒机制

    public class ThreadNotifySample { public static void main(String[] args) { // Res res = new Res(); / ...

  6. Java 多线程 线程的五种状态,线程 Sleep, Wait, notify, notifyAll

    一.先来看看Thread类里面都有哪几种状态,在Thread.class中可以找到这个枚举,它定义了线程的相关状态: public enum State { NEW, RUNNABLE, BLOCKE ...

  7. C++并发编成 03 线程同步

    这一节主要讲讲线程同步的方式,C++ 11中提供了丰富的线程同步元语,如condition_variable,futrue,std::packaged_task<>,std::promis ...

  8. wait()方法写在while循环中可以在线程接到通知后再一次判断条件

    wait()方法写在while循环中可以在线程接到通知后再一次判断条件 synchronized public String pop() { String returnValue = "&q ...

  9. 解决c#所有单线程单元(STA)线程都应使用泵式等待基元(如 CoWaitForMultipleHandles),并在运行时间很长的操作过程中定期发送消息。 转载

    最近做一个后来程序,启动了事务后有一段操作业务,当运行一段时间后,出现这个异常 CLR 无法从 COM 上下文 0x1b1c38 转换为 COM 上下文 0x1b1da8,这种状态已持续 60 秒.拥 ...

随机推荐

  1. 5G如何让智能手机再次变得丑陋?

    第一批5G移动终端将于明年到货,这意味着智能手机制造商现在正在研究细节.与过去十年智能手机所看到的很多其他组件改进不同,像更好的相机,更快的处理器和更亮的屏幕,5G无线电将需要一些设计上的妥协,而且看 ...

  2. QtCreator/lib/qtcreator/plugins/libHelp.so: 无法加载库

    解决方法: 终端命令:sudo apt-get install libqt4-dev sudo apt-get install libgstreamer0.10-dev sudo apt-get in ...

  3. centos 6.5 配置阿里云 yum 镜像

    配置国内镜像目的是为了加速软件下载安装速度,参考链接:http://mirrors.aliyun.com/help/centos 备份.养成文件操作前备份的习惯 cd /etc/yum.repos.d ...

  4. leetcode-15双周赛-1287-有序数组中出现次数超过25%的元素

    题目描述: 方法一:二分法 class Solution: def findSpecialInteger(self, arr: List[int]) -> int: span = len(arr ...

  5. macOS 和 Linux 的内核区别

    有些人可能会认为 macOS 和 Linux 内核之间存在相似之处,因为它们可以处理类似的命令和类似的软件.有些人甚至认为苹果公司的 macOS 是基于 Linux 的.事实上是,两个内核有着截然不同 ...

  6. kNN(从文本文件中解析数据)

    # 准备数据:从文本文件中解析数据# 在kNN.py中创建名为file2matrix的函数,处理输入格式问题# 该函数的输入为文件名字符串,输出为训练样本矩阵和类标签向量# 将文本记录到转换Numpy ...

  7. Buuctf | sqli-labs

    这个是赵师傅给我们提供的训练靶场,最好都打一遍,但是出于找flag的角度,特此记录一下,flag在哪里[没错,我就是喜欢我的蓝变红,哈] ?id=1' :报错,说明就是用这个闭合的 ?id=0' un ...

  8. vue绑定属性、绑定class及绑定style

    1.绑定属性  v-bind 或者 : 例如:<img :src="pic_src" /> <template> <div id="app& ...

  9. 前端每日实战:33# 视频演示如何用纯 CSS 创作牛奶文字变换效果

    效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/MGNWOm 可交互视频教程 此视频 ...

  10. Archive.org:互联网档案馆

    Archive.org:互联网档案馆   2009年的最后一天,辞旧迎新,互联网也同样如此,在过往40年的基础上一步步积累发展.对于我们而言很希望通过以往的每个网页.见证和找寻历史,这就是今天所介绍的 ...