1.为了支撑多线程之间的协作,JDK提供了两个非常重要的线程接口:等待wait()方法和通知notify()方法。

这两个方法并不是在Thread类中的,而是输出在Object类。这意味着任何对象都可以调用这两个方法。

 这两个方法如下

 当在一个对象实例上调用wait()方法后,当前线程就会在这个对象上等待。

 比如,在线程A中,调用了obj.wait()方法,那么线程A就会停止继续执行,转为等待状态。等待到何时结束呢?线程A会一直等到其他线程调用了obj.notity()方法为止。

2.wait()方法和notify()方法究竟是如何工作的呢?

  如果一个线程调用了object.wait()方法,那么它就会进入object对象的等待队列,这个队列中,可能会有多个线程,因为系统运行多个线程同时等待某一个对象,

  当object.notify()方法被调用的时候,它就会从这个等待队列中随机选择一个线程,并进行唤醒。

  除notity()方法外,Object对象还有一个类似的notifyAll()方法,它和notity方法的功能基本一致,不同的是,它会唤醒在这个等待队列中所有等待的线程,而不是随机一个。

  object.wait()方法并不能随便调用。它必须包含在对象的synchronzied语句中,无论是wait()方法或者notity()方法都需要首先获得目标对象的一个监视器。

  如图,其中T1和T2表示两个线程,T1在正确执行wait()方法前,必须获得object对象的监视器,而wait()方法执行之后会释放这个监视器。

这样做的目的是使其他等待在object对象上的线程不至于因为T1的休眠而全部无法正常执行。

  线程T2在notity()方法调用前,也必须获得object对象的监视器。此时T1已经释放了这个监视器。所以T2可以顺利获得object对象的监视器。

接着,T2执行了notify()方法尝试唤醒一个等待线程,这里假设唤醒了T1,T1被唤醒后,要做的第一件事并不是执行后续代码,而是要尝试重新

获得object对象的监视器,而这个监视器也正是T1在wait()方法执行前所持有的那个。

如果暂时无法获得,则T1还必须等待这个监视器。当监视器顺利获得后,T1才可以在真正意义上继续执行。

3.为了方便理解,简单的案例:

/**
* wait和 notify 的学习
* @author wm
* @date 2019/9/18 15:15
*/
public class SimpleWN {
final static Object object = new Object(); public static class T1 extends Thread{
public void run() {
synchronized (object){
System.out.println(System.currentTimeMillis()+":T1 start! ");
System.out.println(System.currentTimeMillis()+":T1 wait for object");
try {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(System.currentTimeMillis()+":T1 end! ");
}
}
} public static class T2 extends Thread{
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 {
object.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
} public static void main(String[] args) {
Thread t1 = new T1();
Thread t2 = new T2();
t1.start();
t2.start();
}
}

 上述代码中,开启了T1和T2两个线程。T1执行了object.wait()方法。执行wait()方法前,T1先申请object的对象锁。

因此,在执行object.wait()时,它持有的是object的对象锁的。wait()方法执行后,T1会进行等待,并释放object对象锁。

T2在执行notity()方法之前也会先获得object的对象锁,这里为了让结果明显,特意在notity()方法执行之后,让T2休眠2秒,

这样做可以更明显地说明,T1在得到notity()方法通知后,还是会先尝试重新获得object的对象锁。

执行结果:

1570675715571:T1 start!
1570675715571:T1 wait for object
1570675715571:T2 start! notify one thread
1570675715571:T2 end!
1570675715571:T1 end!

在T2通知T1继续执行后,T1并不能立即继续执行,而是要等待T2释放object的锁,并重新成功获得锁后,才能继续执行;

4.Object.wait()方法和Thread.sleep()方法都可以让线程等待若干时间,除wait()方法可以被唤醒外,

另外一个主要区别就是wait()方法会释放目标对象的锁,而Thread.sleep()方法不会释放任何资源。

多线程-等待(Wait)和通知(notify)的更多相关文章

  1. Java多线程8:wait()和notify()/notifyAll()

    轮询 线程本身是操作系统中独立的个体,但是线程与线程之间不是独立的个体,因为它们彼此之间要相互通信和协作. 想像一个场景,A线程做int型变量i的累加操作,B线程等待i到了10000就打印出i,怎么处 ...

  2. java多线程15 :wait()和notify() 的生产者/消费者模式

    什么是生产者/消费者模型 一种重要的模型,基于等待/通知机制.生产者/消费者模型描述的是有一块缓冲区作为仓库,生产者可将产品放入仓库,消费者可以从仓库中取出产品,生产者/消费者模型关注的是以下几个点: ...

  3. java多线程14 :wait()和notify()/notifyAll()

    轮询 线程本身是操作系统中独立的个体,但是线程与线程之间不是独立的个体,因为它们彼此之间要相互通信和协作. 想像一个场景,A线程做int型变量i的累加操作,B线程等待i到了10000就打印出i,怎么处 ...

  4. c/c++ 多线程 等待一次性事件 future概念

    多线程 等待一次性事件 future概念 背景:有时候,一个线程只等待另一个线程一次,而且需要它等待的线程的返回值. 案例:滴滴叫车时,点完了叫车按钮后,叫车的后台线程就启动了,去通知周围的出租车.这 ...

  5. c/c++ 多线程 等待一次性事件 异常处理

    多线程 等待一次性事件 异常处理 背景:假设某个future在等待另一个线程结束,但是在被future等待的线程里发生了异常(throw一个异常A),这时怎么处理. 结果:假设发生了上面的场景,则在调 ...

  6. c/c++ 多线程 等待一次性事件 std::promise用法

    多线程 等待一次性事件 std::promise用法 背景:不是很明白,不知道为了解决什么业务场景,感觉std::async可以优雅的搞定一切的一次等待性事件,为什么还有个std::promise. ...

  7. c/c++ 多线程 等待一次性事件 packaged_task用法

    多线程 等待一次性事件 packaged_task用法 背景:不是很明白,不知道为了解决什么业务场景,感觉std::asynck可以优雅的搞定一切,一次等待性事件,为什么还有个packaged_tas ...

  8. Java多线程:线程状态以及wait(), notify(), notifyAll()

    一. 线程状态类型1. 新建状态(New):新创建了一个线程对象.2. 就绪状态(Runnable):线程对象创建后,其他线程调用了该对象的start()方法.该状态的线程位于可运行线程池中,变得可运 ...

  9. 多线程(五)~ wait/notify机制(等待/通知)

    首先我们来看一张图,这张图描述了线程操作的几个步骤. 图已经描述的很清楚了,这里除了wait()之外,其他的前面都已经接触过了. 这一章我们主要来说一下和wait()相关的操作,其实和wait()相关 ...

随机推荐

  1. Qt5教程: (5) Lambda匿名函数的使用

    Lambda是C++11的新特性, 首先看看你的.pro项目文件里有没有CONFIG += c++11这句话, 没有就加上. 下面新建一个工程, 具体步骤就不多说了 然后给主窗口添加一个按钮b, 并且 ...

  2. vc++源码免杀特殊技巧

    一.Debug 和 Release 编译方式的区别: Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序.Release 称为发布版本,它往往是进行了各种优化,使得程序 ...

  3. PHP 插入排序 -- 直接插入排序

    1)直接插入序 -- Straight Insertion Sort 时间复杂度 :O(n^2) 适用条件: 适合记录数不多的情况 1 <?php 2 $a = [0 =>3,4,5,1, ...

  4. muduo Library

    muduo是由陈硕(http://www.cnblogs.com/Solstice)开发的一个Linux多线程网络库,采用了很多新的Linux特性(例如eventfd.timerfd)和GCC内置函数 ...

  5. 7.Linux文件编辑之Vim

    1.VIM基本概述 1.什么是VIM? vi和vim是Linux下的一个文本编辑工具.(可以理解为windows的记事本,或word文档) 2.为什么要使用VIM? 因为Linux系统一切皆为文件,而 ...

  6. SpringBoot-Mysql模板多数据源加载

    SpringBoot-Mysql模板多数据源加载 qq交流群: 812321371 微信交流群: MercyYao 简介 在 java 项目里常用到 mysql 多数据源操作.结合 springboo ...

  7. 基于 HTML5 Canvas 的楼宇自控系统

    前言 楼宇自控是指楼宇中电力设备,如电梯.水泵.风机.空调等,其主要工作性质是强电驱动.通常这些设备是开放性的工作状态,也就是说没有形成一个闭环回路.只要接通电源,设备就在工作,至于工作状态.进程.能 ...

  8. SpringBoot中如何优雅的读取yml配置文件?

    YAML是一种简洁的非标记语言,以数据为中心,使用空白.缩进.分行组织数据,从而使得表示更加简洁易读.本文介绍下YAML的语法和SpringBoot读取该类型配置文件的过程. 本文目录 一.YAML基 ...

  9. 小白学微信小程序

    奔着实用性的目的-测试孩子的认字量,开发了一个微信小程序-测字大王.上下班路上看书看了一个星期,代码前后共写一个星期.现在小程序已经对外开放,share下我的开发过程吧. 一 工具准备 首先先过一篇 ...

  10. 【朝花夕拾】跨进程通信,你只知道AIDL,就OUT了

    一.前言 提起跨进程通信,大多数人首先会想到AIDL.我们知道,用AIDL来实现跨进程通信,需要在客户端和服务端都添加上aidl文件,并在服务端的Service中实现aidl对应的接口.如果还需要服务 ...