wait()、notify()方法原理,以及使用注意事项
wait、notify原理
在前面以经说到对象锁的本质,实际上是对象头的一个监视器锁的数据结构。这个结构如下:
(图片来源于网络)
几个线程一起竞争对象的锁(enter),只有一个能成功(acquire),成功的线程记录在The Owner结构中。调用wait、notify运行流程如下:
(1) 现有一个对象o,锁正在被线程 t1 持有,调用wait()方法后,线程 t1 将会被"晾到" (实际上仅仅是记录到) Wait Set 结构中。
(2)然后将会有另一个线程 t2 获取到锁,The Owner记录的变成了 t2 线程。
(3)t2 线程不需要 o的锁时,调用o.notify()/o.notifyAll()方法,对象o就会告诉 Wait Set结构中记录的线程们:你们又可以来竞争我啦,我的锁现在没被人持有。
简单的说就是:wait是对象通知持有自己锁的线程释放我的锁,notify()/notifyAll()就是对象通知刚刚被自己晾在一边的线程又可以来竞争我的锁了。我想到了一个比较贴切的比喻:
客人(线程)来拜访主人(对象),必须获得主人的时间权(锁),且主人同时只能接待一人(互斥)。
正在客厅接待一名客人时,因为一些原因主人必须先接待另一位客人,这时主人请当前客人去另一间房里等待,让出自己的时间权(wait方法)
主人在客厅接待另一位客人,接待完毕后,让前一位(也可能有几位)在另一间房等待的客人再来到客厅,继续接待(notify/notifyAll方法)
wait、notify要放在同步块中
其实很简单,如果不在同步块中,线程都没有取得对象的锁,又谈何让对象通知线程释放锁、或者来竞争锁呢?也许就通知到Main线程了。如果确实不放到同步块中,则会产生 Lost-wake的问题,即丢失唤醒,以上一篇中生产者消费者例子来说:
生产者线程发现箱子满了确定必须等待,但是由于wait没在同步块中,由于生产者线程此时还没有等待。
消费者线程从缓冲区消费一个产品后调用notify()方法,上个notify消息将被忽略。
生产者线程调用wait()方法并进入等待状态,得不到通知了。
因此,由于这里的竞争条件,我们可能在丢失一个通知,如果我们使用缓冲区或者只有一个产品,生产者线程将永远等待,你的程序也就挂起了。
wait()、notify()方法原理,以及使用注意事项的更多相关文章
- 【细语】C#之扩展方法原理及其使用
1.写在前面 今天群里一个小伙伴问了这样一个问题,扩展方法与实例方法的执行顺序是什么样子的,谁先谁后(这个问题会在文章结尾回答).所以写了这边文章,力图从原理角度解释扩展方法及其使用. 以下为主要内容 ...
- Java使用wait() notify()方法操作共享资源
Java多个线程共享资源: 1)wait().notify()和notifyAll()方法是本地方法,并且为final方法,无法被重写. 2)调用某个对象的wait()方法能让当前线程阻塞,并且当前线 ...
- 并发编程之 wait notify 方法剖析
前言 2018 元旦快乐. 摘要: notify wait 如何使用? 为什么必须在同步块中? 使用 notify wait 实现一个简单的生产者消费者模型 底层实现原理 1. notify wait ...
- Java使用wait() notify()方法操作共享资源详解_java - JAVA
文章来源:嗨学网 敏而好学论坛www.piaodoo.com 欢迎大家相互学习 Java多个线程共享资源: 1)wait().notify()和notifyAll()方法是本地方法,并且为final方 ...
- 高并发之wait notify notifyAll原理详解
public class WaitTest { public void testWait(){ System.out.println("Start-----"); try { wa ...
- java 多线程:线程通信-等待通知机制wait和notify方法;(同步代码块synchronized和while循环相互嵌套的差异);管道通信:PipedInputStream;PipedOutputStream;PipedWriter; PipedReader
1.等待通知机制: 等待通知机制的原理和厨师与服务员的关系很相似: 1,厨师做完一道菜的时间不确定,所以厨师将菜品放到"菜品传递台"上的时间不确定 2,服务员什么时候可以取到菜,必 ...
- join方法原理
join()方法--原理同wait方法 如果不知道保护性暂停是啥的可以参考一下上一篇文章 https://www.cnblogs.com/duizhangz/p/16222854.html join方 ...
- java多线程详解(6)-线程间的通信wait及notify方法
Java多线程间的通信 本文提纲 一. 线程的几种状态 二. 线程间的相互作用 三.实例代码分析 一. 线程的几种状态 线程有四种状态,任何一个线程肯定处于这四种状态中的一种:(1). 产生(New) ...
- [转]js中几种实用的跨域方法原理详解
转自:js中几种实用的跨域方法原理详解 - 无双 - 博客园 // // 这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同 ...
随机推荐
- 头部姿态估计 - OpenCV/Dlib/Ceres
基本思想 通过Dlib获得当前人脸的特征点,然后通过旋转平移标准模型的特征点进行拟合,计算标准模型求得的特征点与Dlib获得的特征点之间的差,使用Ceres不断迭代优化,最终得到最佳的旋转和平移参数. ...
- jQuery通过id和name获取值的区别
$(#'id').函数 $("input[name='name']")
- .NET Core on K8S学习实践系列文章索引(Draft版)
一.关于这个系列 自从去年(2018年)底离开工作了3年的M公司加入X公司之后,开始了ASP.NET Core的实践,包括微服务架构与容器化等等.我们的实践是渐进的,当我们的微服务数量到了一定值时,发 ...
- Windows上切换java8和java11
Windows上安装了java8和java11,时不时要切换,于是思考写行命令解决.思路是修改java_home变量.我的java_home变量是设置在系统级别的. 修改环境变量有2个命令,set和s ...
- Python基础总结之异常、调试代码第十二天开始(新手可相互督促)
年薪20万的梦想,加油! 我们在写代码的时候,控制台经常会报错,因为某种错误,导致我们的程序停止,且不再运行下面的代码. 我们看一个错误的代码示例: def add_1(): #没有参数 print( ...
- 进军pc市场 华为剑走偏锋可有戏?
尽管官方并未正式公布,但在前段时间,华为将要进军PC市场的消息在业内传得沸沸扬扬,据知情人士曝料,其第一款个人电脑将在今年4月上线.而华为将进军PC市场的消息,对其他智能手机厂商来说又意味着什么呢? ...
- 【React踩坑记二】react项目实现JS路由跳转
这里使用的是4.31版本的react-router-dom "react-router-dom": "^4.3.1", 直接使用以下代码即可实现路由跳转 thi ...
- A solution to the never shortened to-do list
I once told my younger sister my learning system, and the basic five doctrines of my methodology. Bu ...
- kafka同步异步消费和消息的偏移量(四)
1. 消费者位置(consumer position) 因为kafka服务端不保存消息的状态,所以消费端需要自己去做很多事情.我们每次调用poll()方法他总是返回已经保存在生产者队列中还未被消费者消 ...
- 消息中间件-activemq实战整合Spring之Topic模式(五)
这一节我们看一下Topic模式下的消息发布是如何处理的. applicationContext-ActiveMQ.xml配置: <?xml version="1.0" enc ...