为什么 wait 方法要在 synchronized 中调用?
作者:Yujiaao
来源:https://segmentfault.com/a/1190000019962661
一个有难度的 Java 问题,wait 和 notify。
它们是在有 synchronized 标记的方法或 synchronized 块中调用的,因为 wait 和 nodify 需要监视对其调用的 Object。
大多数Java开发人员都知道对象类的 wait(),notify() 和 notifyAll() 方法必须在 Java 中的 synchronized 方法或 synchronized 块中调用, 但是我们想过多少次, 为什么在 Java 中 wait, notify 和 notifyAll 来自 synchronized 块或方法?
最近这个问题在Java面试中被问到我的一位朋友,他思索了一下,并回答说: 如果我们不从同步上下文中调用 wait() 或 notify() 方法,我们将在 Java 中收到 IllegalMonitorStateException。
他的回答从实际效果上是正确的,但面试官对这样的答案不会完全满意,并希望向他解释这个问题。面试结束后他和我讨论了这个问题,我认为他应该告诉面试官关于 Java 中 wait()和 notify()之间的竞态条件,如果我们不在同步方法或块中调用它们就可能存在。
让我们看看竞态条件如何在 Java 程序中产生。它也是流行的线程面试问题之一。
为什么要等待来自 Java中的 synchronized 方法的 wait方法为什么必须从 Java 中的 synchronized 块或方法调用 ?
我们主要使用 wait(),notify() 或 notifyAll() 方法用于 Java 中的线程间通信。一个线程在检查条件后正在等待,例如,在经典的生产者 - 消费者问题中,如果缓冲区已满,则生产者线程等待,并且消费者线程通过使用元素在缓冲区中创建空间后通知生产者线程。
调用notify() 或 notifyAll() 方法向单个或多个线程发出一个条件已更改的通知,并且一旦通知线程离开 synchronized 块,正在等待的所有线程开始获取正在等待的对象锁定,幸运的线程在重新获取锁之后从 wait() 方法返回并继续进行。
让我们将整个操作分成几步,以查看Java 中 wait() 和 notify() 方法之间的竞争条件的可能性,我们将使用Produce Consumer 线程示例更好地理解方案:
Producer 线程测试条件(缓冲区是是否已满)并确认是否需要等待(如果发现缓冲区已满则需要等待)。
Consumer 线程在使用缓冲区中的元素后,设置条件。
Consumer 线程调用 notify() 方法; 这是不会被听到的,因为 Producer 线程还没有等待。
Producer 线程调用 wait() 方法并进入等待状态。
因此,由于竞态条件,我们可能会丢失通知,如果我们使用缓冲区或只使用一个元素,生产线程将永远等待,你的程序将挂起。
“在Java 同步中等待 notify 和 notifyAll 现在让我们考虑如何解决这个潜在的竞态条件?这个竞态条件通过使用 Java 提供的 synchronized 关键字和锁定来解决。为了调用 wait(),notify() 或 notifyAll(),必须获得对我们调用方法的对象的锁定。
由于 Java 中的 wait() 方法在等待之前释放锁定并在从 wait() 返回之前重新获取锁定方法,我们必须使用这个锁来确保检查条件(缓冲区是否已满) 和设置条件 (从缓冲区获取元素) 是原子的,这可以通过使用 synchronized 方法或块来实现。
我不确定这是否是面试官实际期待的,但这个我认为至少有意义,请纠正我如果我错了,请告诉我们是否还有其他令人信服的理由调用 wait(),notify() 或 Java 中的 notifyAll() 方法。
总结一下,我们用 Java 中的 synchronized 方法或 synchronized 块调用 Java 中的 wait(),notify() 或 notifyAll() 方法来避免:
Java 会抛出
IllegalMonitorStateException
,如果我们不调用来自同步上下文的wait(),notify()或者notifyAll()方法。Javac 中 wait 和 notify 方法之间的任何潜在竞争条件。
为什么 wait 方法要在 synchronized 中调用?相关推荐
- vue怎么调用子元素的方法_vue 父组件中调用子组件函数的方法
vue 父组件中调用子组件函数的方法 在父组件中调用子组件的方法: 1.给子组件定义一个ref属性.eg:ref="childItem" 2.在子组件的methods中声明一个函数 ...
- java 调用祖父方法_在Java中调用祖父母方法:您不能
java 调用祖父方法 在文章保护的重点中,我详细介绍了"受保护"如何扩展"包私有"访问. 我在那儿写道: 你能做的是 覆盖子类中的方法或 使用关键字super ...
- c语言调用c 方法,C语言代码中调用C++代码的方法示例
由于历史原因,以及不同开发人员的技术偏好,C语言和C++语言都有一些独有的非常有价值的项目,因而两种语言的互操作,充分利用前人造的轮子是一件非常有价值的事情. C++代码调用C代码很简单,只要分别在包 ...
- c 调用html方法,如何在C中调用eval()?
我现在已经验证了eval方法与IE9,IE10和IE11一致(错误检查跳过了错误): CComVariant result; CComDispatchDriver disp = m_htmlWindo ...
- 【Golang】实现企业微信消息通知的方法(可在接口中调用)
1.问题背景 1.在一次实际的项目中,需要在一个应用中发送消息提醒相关人员提交对应的表单.于是我查阅了企业微信开发文档有关消息提醒部分,然后按照其指导,实现了如下效果: 2.解决方案: 首先我们需要创 ...
- python方法调用名字不一样_python中调用父类同名方法
知识回顾: 上节我们学习了类的构造方法. Python中构建构造方法主要使用__init__魔法方法. 实际项目操作中,由于类的继承导致可能覆盖同名的构造方法,导致只能使用子类的构造,而无法调用父类的 ...
- 【Groovy】Groovy 脚本调用 ( Groovy 类中调用 Groovy 脚本 | 参考 Script#evaluate 方法 | 创建 Binding 对象并设置 args 参数 )
文章目录 一.Groovy 类中调用 Groovy 脚本 1.参考 Script#evaluate 方法分析 Groovy 类中调用 Groovy 脚本 2.创建 Binding 对象并设置 args ...
- 【Groovy】闭包 Closure ( 闭包中调用 Groovy 脚本中的方法 | owner 与 delegate 区别 | 闭包中调用对象中的方法 )
文章目录 一.闭包中调用 Groovy 脚本中的方法 二.owner 与 delegate 区别 三.闭包中调用 Groovy 对象中的方法 一.闭包中调用 Groovy 脚本中的方法 在 Groov ...
- 本地方法(JNI)——从java 程序中调用C函数
[0]README 1) 本文部分文字描述 转自 core java volume 2 , 旨在理解 本地方法--从java 程序中调用C函数 的基础知识 : 2) for source code, ...
最新文章
- python代码变量作业_python - 是否可以在Jenkins的代码中注入变量,然后像往常一样运行作业? - SO中文参考 - www.soinside.com...
- 风水学是天气预测模型
- 学习Vim有什么好处? [关闭]
- First Week :Linux系统学习
- 如何给 Chrome 开发者工具设置 Material Design 风格的主题外观
- P7516-[省选联考2021A/B卷]图函数【bfs】
- 浅谈项目管理中的四要素
- mybatis学习(5):安装 SQL Server installsharewowdir命令值无效的问题
- 【C++入门】从C到C++
- 业务安全(逻辑漏洞)
- drozer安全测试
- PHP轻量级博客 typecho插件安装教程
- Rundll32.exe的小理解
- 微机原理与接口技术模拟试题微型计算机中主要包括,微机原理与接口技术模拟试题...
- 弘兵金融学院 站在山顶 看不见山
- 纪录片:《独立游戏大电影》
- C++ 调用 Python 代码 - Clion QT混合编程 ,各取长处。
- 一分钟告诉你究竟DevOps是什么鬼?
- pythonrpg游戏_python实现的简单RPG游戏流程实例
- 用什么方法可以改变摄像机逆光补偿