深入理解 Java 中的线程间通信:`wait()`, `notify()`, `notifyAll()`
引言
在多线程编程中,线程间通信是一个重要且复杂的主题。Java 提供了一套基本的机制来实现线程间通信,即使用 wait(), notify(), 和 notifyAll() 方法。这些方法由 Object 类提供,用于协调多个线程对共享资源的访问。本文将详细介绍这些方法的工作原理、使用场景以及一些实际示例。
基本概念
wait()
wait() 方法使当前线程进入等待状态,直到另一个线程调用 notify() 或 notifyAll() 方法唤醒它。调用 wait() 方法时,线程必须持有该对象的监视器锁(即必须在同步块或同步方法内调用 wait())。
notify()
notify() 方法唤醒在此对象监视器上等待的单个线程。如果有多个线程在等待,则其中一个线程将被唤醒,具体哪个线程被唤醒取决于线程调度器的实现。
notifyAll()
notifyAll() 方法唤醒在此对象监视器上等待的所有线程。这些线程将竞争重新获得该对象的监视器锁,并继续执行。
使用场景
生产者-消费者模式
生产者-消费者模式是多线程编程中的经典问题。在这个模式中,生产者线程生成数据并将其放入共享缓冲区,而消费者线程从缓冲区中取出数据进行处理。为了避免缓冲区溢出和空取,生产者和消费者需要协调工作。
示例代码
生产者-消费者实现
以下是一个使用 wait() 和 notify() 实现的简单生产者-消费者示例:
import java.util.LinkedList;
import java.util.Queue;class ProducerConsumer {private final Queue<Integer> queue = new LinkedList<>();private final int MAX_SIZE = 10;public void produce() throws InterruptedException {int value = 0;while (true) {synchronized (this) {while (queue.size() == MAX_SIZE) {wait();}queue.add(value);System.out.println("Produced: " + value);value++;notify();Thread.sleep(100); // 模拟生产过程}}}public void consume() throws InterruptedException {while (true) {synchronized (this) {while (queue.isEmpty()) {wait();}int value = queue.poll();System.out.println("Consumed: " + value);notify();Thread.sleep(100); // 模拟消费过程}}}
}public class Main {public static void main(String[] args) {ProducerConsumer pc = new ProducerConsumer();Thread producerThread = new Thread(() -> {try {pc.produce();} catch (InterruptedException e) {Thread.currentThread().interrupt();}});Thread consumerThread = new Thread(() -> {try {pc.consume();} catch (InterruptedException e) {Thread.currentThread().interrupt();}});producerThread.start();consumerThread.start();}
}
代码解释
ProducerConsumer类中定义了一个共享队列queue和一个最大容量MAX_SIZE。produce()方法生成数据并将其放入队列。当队列已满时,调用wait()进入等待状态。consume()方法从队列中取出数据。当队列为空时,调用wait()进入等待状态。- 当生产者生产了一个数据后,调用
notify()唤醒等待的消费者。消费者同样在消费了一个数据后调用notify()唤醒等待的生产者。
注意事项
在同步块或同步方法内使用
wait(), notify(), 和 notifyAll() 方法必须在同步块或同步方法内调用,因为它们需要持有对象的监视器锁。如果在非同步块或非同步方法内调用这些方法,将抛出 IllegalMonitorStateException 异常。
避免虚假唤醒
虚假唤醒(spurious wakeups)是指线程在没有收到 notify() 或 notifyAll() 通知的情况下被唤醒。因此,应该总是使用循环来调用 wait() 方法,而不是使用 if 语句:
synchronized (this) {while (condition) {wait();}// 执行代码
}
使用 notifyAll() 而非 notify()
在某些情况下,使用 notifyAll() 比 notify() 更安全,因为 notifyAll() 可以唤醒所有等待的线程,避免某些线程永远等待的情况。例如,在有多个生产者和消费者时,notifyAll() 更能确保公平性。
结论
通过使用 wait(), notify(), 和 notifyAll() 方法,Java 提供了基本的线程间通信机制,可以有效地解决线程间的协作问题。理解并正确使用这些方法,对于编写高效且安全的多线程程序至关重要。
希望本文能帮助你理解 Java 中的线程间通信机制及其应用场景。如果你有任何问题或建议,欢迎留言讨论。
相关文章:
深入理解 Java 中的线程间通信:`wait()`, `notify()`, `notifyAll()`
引言 在多线程编程中,线程间通信是一个重要且复杂的主题。Java 提供了一套基本的机制来实现线程间通信,即使用 wait(), notify(), 和 notifyAll() 方法。这些方法由 Object 类提供,用于协调多个线程对共享资源的访问。本文将详细介绍这些方法…...
23种设计模式【创建型模式】详细介绍之【单例模式】
23种设计模式【创建型模式】详细介绍之【单例模式】 设计模式的分类和应用场景总结单例模式1. 概述2. 实现方式2.1 饿汉式单例模式2.2 懒汉式单例模式(非线程安全)2.3 懒汉式单例模式(线程安全) 3. 单例模式的优缺点3.1 优点3.2 缺…...
某汽车配件制造公司任职资格体系项目成功案例纪实
——基于岗位特点和核心能力要求,分层分级能力测评,实现个性化人才培养 【客户行业】生产制造;汽车配件制造 【问题类型】任职资格体系建立;人才管理系统 【客户背景】 某汽车配件制造公司是一家专注于汽车配件研发、生产和销…...
【Linux】生物信息学常用基本命令
wget网址用于直接从网上下载某个文件到服务器,当然也可以直接从网上先把东西下到本地然后用filezilla这个软件来传输到服务器上。 当遇到不会的命令时候,可以使用man “不会的命令”来查看这个命令的详细信息。比如我想要看看ls这个命令的详细用法&…...
React Native V0.74 — 稳定版已发布
嗨,React Native开发者们, React Native 世界中令人兴奋的消息是,V0.74刚刚在几天前发布,有超过 1600 次提交。亮点如下: Yoga 3.0New Architecture: Bridgeless by DefaultNew Architecture: Batched onLayout UpdatesYarn 3 for New Projects让我们深入了解每一个新亮点…...
Python面试宝典第4题:环形链表
题目 给你一个链表的头节点 head ,判断链表中是否有环。如果存在环 ,则返回 true 。 否则,返回 false 。 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环…...
Kubernetes (K8s) 底层原理
Kubernetes (K8s) 的底层原理涉及多个关键组件和概念,确保容器化应用程序的自动化部署、扩展和管理。以下是 Kubernetes 的底层原理及其关键组件的详细描述。 核心组件 Etcd 功能:分布式键值存储,用于存储集群的所有数据,包括配置…...
解析Kotlin中的委托(包括类委托,属性委托)【笔记摘要】
1.委托模式 委托模式:操作对象不会去处理某段逻辑,而是会把工作委托给另外一个辅助对象去处理。 例如我们要设计一个自定义类的来实现Set,可以将该实现委托给另一个对象: class MySet<T> (val helperSet: HashSet<T>…...
vue3+ts+uniapp+vite+pinia项目配置
开发环境: node >18,npm >8.10.2,vue < 3.2.31 安装项目 npx degit dcloudio/uni-preset-vue#vite-ts vue3-uniapp 1、引入样式规范 npm add -D eslint eslint-config-airbnb-base eslint-config-prettier eslint-import-resolv…...
大数据开发语言 Scala(四):面向对象编程
目录 1. 概述 2. 面向对象编程的基本概念 2.1 类和对象 2.2 继承和多态 2.3 封装和访问控制 3. 面向对象编程在大数据开发中的应用 3.1 Spark中的面向对象编程 3.2 面向对象编程在数据清洗和预处理中 3.3 面向对象编程在机器学习中的应用 4. 面向对象编程的高级特性 …...
C++ //练习 14.31 我们的StrBlobPtr类没有定义拷贝构造函数、赋值运算符及析构函数,为什么?
C Primer(第5版) 练习 14.31 练习 14.31 我们的StrBlobPtr类没有定义拷贝构造函数、赋值运算符及析构函数,为什么? 环境:Linux Ubuntu(云服务器) 工具:vim 解释: 因为…...
通配符和正则表达式之间的关系
通配符和正则表达式(正则)都是用于匹配字符串的工具,但它们的复杂性和用途有所不同。下面是它们之间的主要关系和区别: 通配符 通配符主要用于简单的模式匹配,常见于文件系统操作中,例如在命令行中查找文…...
GY-30光照传感器软件I2C方式驱动代码,基于STM32Cube
GY-30光照传感器的具体资料可以去淘宝搜索然后问卖家要,网上也有,所以这里我就不多嘴了。 VCC连接3到5伏电压,根据文件开头的描述在STM32CubeMX中配置好外设。 STM32Cube开发方式就是4个字“简单直接”,直接上代码。 gy30.h #…...
双相元编程:一种新语言设计方法
本文讨论了编程语言的一种趋势,即允许相同的语法表达 在两个不同阶段或环境(上下文)中执行的计算同时保持跨阶段(上下文)的一致行为。这些阶段通常在时间上(运行时间)或空间上(运行…...
基于SpringBoot校园外卖配送系统设计和实现(源码+LW+调试文档+讲解等)
💗博主介绍:✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者,博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌💗 🌟文末获取源码数据库🌟 感兴趣的可以先收藏起来,…...
茗鹤APS高级计划排程系统,在集团多工厂协同生产下的应用
随着业务规模的扩大和市场的全球化,越来越多的企业选择“总部多工厂基地”的模式,此种模式大幅提升企业的产能与产量,有效分散风险。然后,与之而来的是对企业的管理提出更高的管理要求。多个生产基地不仅面临集团下发的周期性计划…...
分享六款免费u盘数据恢复工具,U盘恢复工具集合【工具篇】
U盘里面的数据丢失了怎么找回?随着数字化时代的深入发展,U盘已成为我们日常生活中不可或缺的数据存储工具。然而,由于各种原因,如误删除、格式化、病毒攻击等,U盘中的数据可能会丢失,给用户带来极大的困扰。…...
Linux 的启动流程
第一步、加载内核 操作系统接管硬件以后,首先读入 /boot 目录下的内核文件。 以我的电脑为例,/boot 目录下面大概是这样一些文件: $ ls /bootconfig-3.2.0-3-amd64config-3.2.0-4-amd64grubinitrd.img-3.2.0-3-amd64initrd.img-3.2.0-4-amd6…...
思维导图插件--jsMind的使用
vue引入jsmind(右键菜单)_jsmind.menu.js-CSDN博客 第一版 vue-JsMind思维导图实现(包含鼠标右键自定义菜单)_jsmind 右键菜单-CSDN博客 // 新增节点addNode() {console.log(this.get_selected_nodeid());this.get_selected_…...
mac上使用finder时候,显示隐藏的文件或者文件夹
默认在finder中是不显示隐藏的文件和文件夹的,但是想创建.gitignore文件,并向里面写入内容,即便是打开xcode也是不显示这几个隐藏文件的,那有什么办法呢? 使用快捷键: 使用finder打开包含隐藏文件的文件夹…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...
C++.OpenGL (20/64)混合(Blending)
混合(Blending) 透明效果核心原理 #mermaid-svg-SWG0UzVfJms7Sm3e {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-icon{fill:#552222;}#mermaid-svg-SWG0UzVfJms7Sm3e .error-text{fill…...
什么是VR全景技术
VR全景技术,全称为虚拟现实全景技术,是通过计算机图像模拟生成三维空间中的虚拟世界,使用户能够在该虚拟世界中进行全方位、无死角的观察和交互的技术。VR全景技术模拟人在真实空间中的视觉体验,结合图文、3D、音视频等多媒体元素…...
高分辨率图像合成归一化流扩展
大家读完觉得有帮助记得关注和点赞!!! 1 摘要 我们提出了STARFlow,一种基于归一化流的可扩展生成模型,它在高分辨率图像合成方面取得了强大的性能。STARFlow的主要构建块是Transformer自回归流(TARFlow&am…...
高效的后台管理系统——可进行二次开发
随着互联网技术的迅猛发展,企业的数字化管理变得愈加重要。后台管理系统作为数据存储与业务管理的核心,成为了现代企业不可或缺的一部分。今天我们要介绍的是一款名为 若依后台管理框架 的系统,它不仅支持跨平台应用,还能提供丰富…...
大数据驱动企业决策智能化的路径与实践
📝个人主页🌹:慌ZHANG-CSDN博客 🌹🌹期待您的关注 🌹🌹 一、引言:数据驱动的企业竞争力重构 在这个瞬息万变的商业时代,“快者胜”的竞争逻辑愈发明显。企业如何在复杂环…...
解决MybatisPlus使用Druid1.2.11连接池查询PG数据库报Merge sql error的一种办法
目录 前言 一、问题重现 1、环境说明 2、重现步骤 3、错误信息 二、关于LATERAL 1、Lateral作用场景 2、在四至场景中使用 三、问题解决之道 1、源码追踪 2、关闭sql合并 3、改写处理SQL 四、总结 前言 在博客:【写在创作纪念日】基于SpringBoot和PostG…...
【R语言编程——数据调用】
这里写自定义目录标题 可用库及数据集外部数据导入方法查看数据集信息 在R语言中,有多个库支持调用内置数据集或外部数据,包括studentdata等教学或示例数据集。以下是常见的库和方法: 可用库及数据集 openintro库 该库包含多个教学数据集&a…...
