Java中的wait()与notify()/notifyAll()

2023-11-11

1、wait()与sleep()/yield()的不同

调用sleep()和yield()时,线程掌握的对象上的锁不会被释放;而调用wait()时,线程掌握的对象上的锁会被释放掉。这一点是需要注意的,也是有意义的。因为调用wait()会释放锁,所以在一个synchronized方法或代码段中调用wait()就意味着该对象中的其它synchronized方法或代码段可以得到执行。这一点至关重要,因为这些操作可以会导致对象发生改变,而这些改变往往是唤醒wait()等待的条件。

2、wait()/notify()/notifyAll()的调用

wait()/notify()/notifyAll()是Object类的一部分,也就是说这些操作是所有对象上都会有的操作,这是有道理的,因为这些操作都伴随着对对象上锁的操作。事实上,只能在synchronized方法或者代码段中调用这些方法(因为不用操作锁,所以sleep()可以在非同步方法里被调用)。如果在非synchronized方法或者代码段中调用这些方法,编译的时候能够通过,但是运行的时候会抛出IllegalMonitorStateException异常,同时伴随着一些含糊的信息,比如“当前线程不是拥有者”。消息的意思是,调用wait()、notify()和notifyAll()之前线程必须掌握对象的锁。

3、notify()与notifyAll()的差别

notify()调用时,如果只有一个线程在当前对象上调用了wait(),这个wait()的调用线程就会被唤醒;如果有多个线程调用了当前对象上的wait()方法,那么这些线程中只有一个会被唤醒,至于唤醒哪一个线程对程序员是未知的。而notifyAll()被调用后,所有调用了当前对象上的wait()的在等待的线程都会被唤醒,这些被唤醒的线程将会重新尝试去获取当前对象上的锁。当然只有一个线程能够获取锁并得到执行,剩下的线程将会被阻塞,需要注意的是这里这些因为竞争没能成功获取锁的线程是处于阻塞状态的,而不是调用wait()后等待被唤醒的状态,它们只要在接下来的执行过程中成功获取锁就可以继续执行,而不要再等待notify()/notifyAll()被调用唤醒它们。

需要注意的是,正常情况下应该使用的是notifyAll(),使用notify()而不是notifyAll()可以被看成是一种优化。因为在当前对象上可能有很多线程调用了wait()在等待,所以使用notifyAll()而不是notify()是更安全的。那么什么时候可以使用notify()呢?如果要使用notify(),那么就需要保证所有的线程等待的都是相同的条件(并且保证在可能的子类中这个条件也是被满足的)。因为只有这样,不论哪个线程被唤醒,这个被唤醒的线程都是恰当的线程,它和其它等待的线程等待的条件都是一样的。如果不同的线程等待的是不同的条件,调用notify()后你就不知道具体等待哪个条件的线程被唤醒了。这时,你就应该调用notifyAll()唤醒所有等待的线程,然后让它们自己在接下来的执行过程中再去判断条件,决定是不是要重新进入到wait()状态。这就涉及到wait()的惯用法。

4、wait()调用的惯用法

在调用wait()时必须使用一个检查感兴趣的条件的while循环包围wait()。这很重要:
- 可能会有不同的线程出于相同的原因(关注相同的条件)在等待同一个锁,第一个被唤醒的线程可能会改变关注的条件(即使你没有那么做,也会有继承你的子类去这样做)。如果属于这种情况,那么这个人物就应该在再次挂起,直至感兴趣的条件发生变化。
- 在一个线程被唤醒的时刻,有可能会有某个其它的线程已经对等待的条件做出改变,从而使得当前的线程不能被执行或者没有必要在执行。此时,应该通过调用wait()将其重新挂起。
- 可能有一组线程出于不同的原因(关注不同的条件)在等待同一个锁(这是就需要使用notifyAll())。这种情况下,所有的线程都会被唤醒,它们需要检查一下是不是自己等待的条件发生了,如果不是就应该再次调用wait()挂起等待。

使用while循环包围wait()的实质就是在线程被唤醒后需要再次检查一下等待的条件,如果条件不满足则应该重新调用wait()继续等待。

    synchronized(sharedMonitor){
        while(!condition){
            sharedMonitor.wait();
        }
    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java中的wait()与notify()/notifyAll() 的相关文章

  • 如何重定向到WEB-INF文件夹中的JSP

    我有一个带有 NAV 的 jsp 其中还包含 UL 和以下元素 如下面的代码所示
  • JFrame 图标在 Ubuntu 12.04 中不显示

    我使用一些图像图标开发了一个 Swing 应用程序 应用程序 jar 文件在 Windows 中按预期工作 但相同的 jar 文件在 Ubuntu 12 04 操作系统上不显示框架的图像图标 我的示例代码 ImageIcon ImageIc
  • 使用 REST API 实现属性/字段级安全

    我正在为支持多租户授权模型的 REST API 构建概念验证 该模型不仅控制用户可以访问哪些对象 还控制对象中的字段 此模型的目标是确保租户管理员只能修改其租户并且只能查看允许的对象属性 我有一个正在开发的现有代码库 可在以下位置公开获取
  • Zuul不转发请求到其他微服务

    我正在使用 Spring Boot 微服务 我已经配置了 eureka zuul 代理和另一个微服务 帐户 如果我直接从帐户拨打电话 则工作正常 帐户和 zuul 服务器都显示在 eureka 上 当我尝试使用 zuul 代理进行访问时 它
  • Java 访问被拒绝

    C Program Files x86 Java jdk1 6 0 17 bin gt javac VendingMachine java VendingMachine java 27 error while writing Vending
  • Java 扫描仪问题 (JFrame)

    我正在尝试使用扫描仪来编辑塔防游戏的级别 但是 它不会将级别 图块图像 更新为自定义文件的级别 0 是草 1 是石头 1 是什么都没有 等等 我发现了错误 但如何修复它 我需要添加 更改什么才能消除这个错误 java lang NullPo
  • Android - 检测电容式触摸屏上的触摸压力?

    我听说过 MotionEvent e float press e getPressure 但这只会在没有触摸时返回 0 当我的手指触摸屏幕时返回 1 是否可以找到手指在触摸电容屏上施加的压力值 或者我的预感是否正确 即这只适用于电阻屏幕 M
  • 高负载应用程序的数据库可扩展性?

    我见过一些应用程序拥有集群 Web 服务器 例如 10 到 20 个服务器 以具有可扩展性 可以在其中分发 在网络服务器之间加载 但我总是看到所有网络服务器都使用单个数据库 现在考虑任何电子商务或铁路 Web 应用程序 其中有数百万用户在任
  • 在 Retrofit 中的 POST 请求中发送空正文

    我的 api 需要一个空的 json 主体 发出帖子请求时 如何在 Retrofit 和 Jackson 中进行设置 我尝试通过null 和空字符串 以及 但无法让它发挥作用 POST my url Call
  • 无法安装 JDK 9,因为“另一个 Java 安装正在进行中”

    我已经在 Windows 10 x64 上使用 JDK 9 一段时间了 但是当我去安装最新的早期版本 b174 时 我首先卸载了以前的版本 像往常一样 然后运行新的安装程序 它失败并显示一个消息框 显示 另一个 Java 安装正在进行中 您
  • Java DocumentBuilder - XML 文件中的缩进错误

    我尝试使用 DocumentBuilder 用 Ja va 编写一个简单的 XML 文件 我期望 XML 文件如下所示
  • 为什么对象可以改变类变量的值?

    由甲骨文提供定义 http docs oracle com javase tutorial java javaOO classvars html 有时 您希望拥有所有对象共有的变量 这是通过 static 修饰符来完成的 声明中带有 sta
  • Java 堆分析因 SIGABRT 崩溃

    我正在尝试分析由 C 编写的方法分配并插入的本机内存JVM通过JNI 我安装了 valgrind version valgrind 3 13 0 并尝试使用以下选项运行 JVM valgrind tool massif massif out
  • Eclipse java 断点 - 目的是什么?

    我正在学习 Android 教程 刚刚进入调试部分 我想知道断点的用途是什么 我还不能告诉 它实际上停止了应用程序 以便我可以确定它运行到该点 或者我可以设置多个断点并将它们用作标记来从断点到断点检查 停止和运行 我的代码 断点是执行停止的
  • 我可以使用本机系统窗口作为父窗口使 JDialog 成为模式吗?

    我有一个 JDialog 窗口 我需要使其成为模态窗口 但父窗口不是 Java 窗口 而是本机 Windows 操作系统窗口 是否可以 不 你不能 您甚至无法不仅引用本机窗口 甚至无法引用运行在其他 JVM 中的 java 应用程序创建的窗
  • java中的Anagram算法

    我想做字谜算法但是 这段代码不起作用 我的错在哪里 例如 des 和 sed 是字谜 但输出不是字谜 同时我必须使用字符串方法 不是数组 public static boolean isAnagram String s1 String s2
  • 从java小程序获取正确的本地IP地址

    我想从我的 java 小程序确定本地 IP 地址 问题是当同一台机器上有多个 IP 地址时 该机器具有 LAN 和互联网连接 掌上电脑 VMWare 这是我的测试 public static void main String args tr
  • Spring MVC 和复选框

    我正在使用 Spring MVC 3 0 并且不能完全看到这个问题的所有部分 我的控制器将生成一个域对象列表 假设有一个简单的 User 对象 具有firstName lastName age 和role 属性 我想在表中输出该用户列表 每
  • 寻找基于循环固定大小数组的双端队列

    我正在寻找一个Deque其具有以下特点 它有固定的大小 如果我在头 尾添加元素 则另一端的元素会丢失 它是基于数组的 所以我可以在恒定时间内访问随机元素 我可以在前面或末尾添加元素 双端队列 我检查了Deque的实施JCF但我没有找到任何合
  • 应用程序中 GC 长时间暂停

    我当前运行的应用程序需要最大堆大小为 16GB 目前我使用以下标志来处理垃圾收集 XX UseParNewGC XX UseConcMarkSweepGC XX CMSInitiatingOccupancyFraction 50 XX Di

随机推荐

  • Java 实现 AES 对称加密算法的加解密

    Java 实现 AES 对称加密算法的加解密 前言 一 对称加密算法简介 1 对称加密 2 加密模式 3 填充模式 二 AES 加解密代码实例 1 生成 AES 密钥 2 AES 加解密 3 AES nonce 加解密 前言 文章字数比较多
  • uniapp 里折叠面板嵌套 uni-collapse 高度不能自适应解决办法

  • python:根据一个列表对另外一个列表排序

    在使用python处理数据时可能会遇到根据列表A对列表B进行排序的问题 记录一下想到的两个方法 方法1 根据列表b中每个元素的下标来获取列表a中对应位置的元素 将其作为排序依据即可 import random a x for x in ra
  • JVM你知道多少?

    1 jvm的内存结构 方法区和堆是所有线程共享的内存区域 而java栈 本地方法栈和程序计数器是运行时线程私有的内存区域 1 Java堆 Heap 是Java虚拟机所管理的内存中最大的一块 Java堆是被所有线程共享的一块内存区域 在虚拟机
  • naive bayes java_Naive Bayes 朴素贝叶斯的JAVA代码实现

    最进写毕业论文找了下贝页斯的资料 这个文章讲的很好 转载下 链接http blog csdn net michael kong nju article details 12623557 comments 1 关于贝叶斯分类 bayes 是一
  • STM32—ADC详解入门(ADC读取烟雾传感器的值)

    目录 一 ADC是什么 二 ADC的性能指标 三 ADC特性 四 ADC通道 五 ADC转换顺序 六 ADC触发方式 七 ADC转化时间 八 ADC转化模式 九 实验 使用ADC读取烟雾传感器的值 1 配置 2 代码 一 ADC是什么 AD
  • MSYS2更换国内源

    今天安装了Msys64 但是Msys64使用的国外源实在太慢 必须更新为国内源 目前测试过国内最快是清华大学的源 我的安装路径为d msys64 为什么要安装在D盘 因为msys64需要不断更新数据和安装自己的软件 也就是说会占用越来越多的
  • 使用mnist数据集实现手写字体的识别

    1 MNIST是一个入门级的计算机视觉数据集 它包含各种手写数字图片 它也包含每一张图片对应的标签 告诉我们这个是数字几 该数据集包括60000行的训练数据集 mnist train 和10000行的测试数据集 mnist test 每一张
  • mysql索引左侧原则,你真的了解吗?

    前言 写这篇文章源自一位杠精同事提了个问题 左侧原则跟where条件顺序有无关系 我想了想 好像是有关系的 不敢确定 但是自己又懒得动手测试 于是发起ETC自动抬杠功能 强行杠了一拨 结果杠输了 接下来即是动手验证 预习执行计划 实践 咱们
  • Something about C

    What the hell How long since I touch with C What a pity I have to work with it now Global variable Better define a globa
  • c++中setw()与setfill()的用法详情

    c 中setw 与setfill 的用法详情 在C 中 setw int n 用来控制输出间隔 例如 cout lt lt s lt
  • 关于自搭网站XAMPP(三)MYSQL增删改查(水)

  • Ubuntu 18.04下载安装以及分区教程

    收藏一下写的超赞的博客 Ubuntu18 04安装教程 超详细的图文教程 安装Ubuntu Linux系统时硬盘分区最合理的方法ubuntu18 04分区设置 也安装过很多次ubuntu了 记录一下最重要的踩坑点 分区完成后会让选择安装启动
  • 算法之字符串匹配一

    目录 前言 BF算法 RK算法 总结 参考资料 前言 字符串匹配指的是一个短点的字符串与一个长点的字符串进行匹配 并确认短的字符串是否在长的字符串中存在 匹配算法有很多 本文介绍两种简单 容易理解的两种算法 BF算法和RK算法 BF算法 B
  • C语言版本数据结构03:顺序表+链表

    今天我们来学习数据结构的第一个顺序结构 顺序表和链表 1 线性表 线性表是我们要学的第一个结构 我们知道一串连续的数字或者字符想要在内存中存储可以用数组 但是我们又知道数组是静态的 那么如果我想要对这组数据进行增删查改呢 这就显现出线性表的
  • Mysql按数字大小排序String字段

    今天做项目的时候 遇到个小小的问题 在数据库中查询的时候 要用String类型的数字进行一下排序 结果是按照字符串排序来处理的 没有达到预想中的效果 于是先是想到将字符转成数字型的 在网上搜了一下 基本上都是这样做的 只不过很多人实现的方式
  • 内存检测工具Dr. Memory的使用

    Dr Memory是一个内存调试工具 它是一个开源免费的内存检测工具 它能够及时发现内存相关的编程错误 比如未初始化访问 内存非法访问 数组越界读 写 以及内存泄露等 它可以在Linux Windows Mac OS和Android操作系统
  • ngrok的使用(超详细)

    1 ngrok简介 百度百科 ngrok 是一个反向代理 通过在公共的端点和本地运行的 Web 服务器之间建立一个安全的通道 ngrok 可捕获和分析所有通道上的流量 便于后期分析和重放 啥玩意 1 其实说白了就是你写一个项目 在PC上完美
  • 微信小程序合法域名配置

    在微信小程序的开发过程中 当需要请求第三方网站数据时 各种教程就直接说调用wx request接口即可 但是当初学者自己用的时候就会出现问题 比如我们这里请求聚合数据的API 里边有不少免费的数据申请就可以使用 调用邮编查询的接口 getP
  • Java中的wait()与notify()/notifyAll()

    1 wait 与sleep yield 的不同 调用sleep 和yield 时 线程掌握的对象上的锁不会被释放 而调用wait 时 线程掌握的对象上的锁会被释放掉 这一点是需要注意的 也是有意义的 因为调用wait 会释放锁 所以在一个s