为什么 wait 方法要在 synchronized 中调用?

简介: 它们是在有 synchronized 标记的方法或 synchronized 块中调用的,因为 wait 和 nodify 需要监视对其调用的 Object。大多数Java开发人员都知道对象类的 wait(),notify() 和 notifyAll() 方法必须在 Java 中的 synchronized 方法或 synchronized 块中调用, 但是我们想过多少次, 为什么在 Java 中 wait, notify 和 notifyAll 来自 synchronized 块或方法?

它们是在有 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 程序中产生。它也是流行的线程面试问题之一。

image.png

为什么要等待来自 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 方法之间的任何潜在竞争条件。


相关文章
|
消息中间件 存储 网络协议
ZMQ/ZeroMQ简介
ZMQ/ZeroMQ简介
|
传感器 物联网
详解MQTT主题和通配符
详解MQTT主题和通配符
2620 0
详解MQTT主题和通配符
|
边缘计算 数据可视化 物联网
node-red介绍
Node-RED最初是IBM在2013年末开发的一个开源项目——基于数据流(dataflow)的可视化编程工具。
node-red介绍
|
8月前
|
人工智能 自然语言处理 API
n8n:流程自动化、智能化利器
流程自动化助你在重复的业务流程中节省时间,可通过自然语言直接创建工作流啦。
1609 9
n8n:流程自动化、智能化利器
LiveCharts 直方图详解,安装和使用,以及常用属性的说明
本文介绍了LiveCharts在WPF中的应用,包括安装方法、基本使用和直方图(LineSeries)的常用属性说明。安装LiveCharts通过NuGet包管理器进行,使用时需在XAML文件中引入相应的命名空间。文章还提供了直方图的属性详解和综合示例,包括线条样式、坐标轴标签、图例位置等设置,以及如何自定义数据点形状。
LiveCharts 直方图详解,安装和使用,以及常用属性的说明
|
SQL 开发框架 关系型数据库
基于SqlSugar的数据库访问处理的封装,支持多数据库并使之适应于实际业务开发中
基于SqlSugar的数据库访问处理的封装,支持多数据库并使之适应于实际业务开发中
|
SQL 关系型数据库 数据库连接
Entity Framework Core 入门教程来袭!快速上手强大的 ORM 工具,开启高效数据库开发之旅!
【8月更文挑战第31天】Entity Framework Core(EF Core)是一个轻量且可扩展的对象关系映射(ORM)框架,允许开发者使用 .NET 语言操作数据库而无需直接编写 SQL 语句。本教程涵盖 EF Core 的安装、数据库上下文创建、数据库连接配置及常见数据库操作(如添加、查询、更新和删除),并介绍如何利用数据库迁移功能安全地更改数据库结构。通过本教程,你可以快速掌握 EF Core 的基本用法,提高开发效率。
2440 0
|
机器学习/深度学习 人工智能 搜索推荐
如何让你的Uno Platform应用秒变AI大神?从零开始,轻松集成机器学习功能,让应用智能起来,用户惊呼太神奇!
【9月更文挑战第8天】随着技术的发展,人工智能与机器学习已融入日常生活,特别是在移动应用开发中。Uno Platform 是一个强大的框架,支持使用 C# 和 XAML 开发跨平台应用(涵盖 Windows、macOS、iOS、Android 和 Web)。本文探讨如何在 Uno Platform 中集成机器学习功能,通过示例代码展示从模型选择、训练到应用集成的全过程,并介绍如何利用 Onnx Runtime 等库实现在 Uno 平台上的模型运行,最终提升应用智能化水平和用户体验。
581 1
|
20天前
|
人工智能 缓存 前端开发
DeepSeek Harness 首发实测 + 入门教程,夯爆了!梁神我错了
DeepSeek Harness + DeepSeek V4 Pro 项目实战保姆级教程!手把手带你从零安装开源 AI 编程工具,开发架构图、知识讲解网站、3D 网页游戏、全栈 AI 应用 4 个项目,覆盖运行模式选择、插件安装与开发,看看能不能对标 Claude。
13233 90
DeepSeek Harness 首发实测 + 入门教程,夯爆了!梁神我错了