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. [CF494B] Obsessive String

    Hamed has recently found a string t and suddenly became quite fond of it. He spent several days tryi ...

  2. nginx::基于Nginx+nginx-rtmp-module+ffmpeg搭建rtmp、hls流媒体服务器

    待续 ffmpeg -re -i "/home/bk/hello.mp4" -vcodec libx264 -vprofile baseline -acodec aac -ar 4 ...

  3. c++11::initializer_list

    #include <initializer_list> template <class T> class initializer_list; initializer_list对 ...

  4. NodeJs编写Cli实现自动初始化新项目目录结构

    应用场景 前端日常开发中,会遇见各种各样的cli,这些工具极大地方便了我们的日常工作,让计算机自己去干繁琐的工作,而我们,就可以节省出大量的时间用于学习.交流.开发. 注释:文章附有源码链接! 使用工 ...

  5. 最简破解-java代码热加载热部署IDEA插件JRebel

    如果经济实力允许的话,还是建议大家去购买收费版.支持原创作者,才能有更好的产品出现. 一.Jrebel插件介绍 JRebel一款帮助我们在开发过程中实现热加载的插件,目前来说,在IDEA中实现热加载最 ...

  6. Mybaits 源码解析 (五)----- 面试源码系列:Mapper接口底层原理(为什么Mapper不用写实现类就能访问到数据库?)

    刚开始使用Mybaits的同学有没有这样的疑惑,为什么我们没有编写Mapper的实现类,却能调用Mapper的方法呢?本篇文章我带大家一起来解决这个疑问 上一篇文章我们获取到了DefaultSqlSe ...

  7. C语言 二叉树的遍历(递归和非递归)

    #include <iostream> #include <cstdio> #include "biTree.h" #include "cstdl ...

  8. codeblocks 调试不停止的解决办法。

    CB的工程路径不能有中文,也不能有空格. 所以一定要全英文路径,而且空格要用下划线代替. 否则,调试的时候,codeblocks不会在断点处停止.

  9. ThreadLocal小试牛刀

    ThreadLocal中保存的数据只能被当前线程私有,不被其它线程可见 证明 声明一个全局的变量threadLocal,初始值为1,通过3个线程对其进行访问修改设置,理论上threadLocal的最终 ...

  10. 数组转换成List集合

    Element[] array = {new Element(1), new Element(2)};List<element> list = new ArrayList<eleme ...