怎么通过 Object 类的 wait/notify 机制在面向对象层面实现初级的线程间协作
怎么通过 Object 类的 wait/notify 机制在面向对象层面实现初级的线程间协作

免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈
在Ja va多线程编程里,让线程之间有序协作,而不是乱成一锅粥,是个基本功。Object 类提供的 wait() 和 notify()(以及它的兄弟 notifyAll())方法,正是实现这种“等待-唤醒”契约的核心工具。简单来说,就是让一个线程在条件不满足时先“歇着”,等另一个线程准备好后再把它“叫醒”。
但这里有个铁律,必须牢记:所有对 wait 和 notify 的调用,都必须老老实实地放在 synchronized 同步块里,而且锁对象,必须就是调用这些方法的那个对象本身。这是整个机制能安全运转的基石。
共享状态对象作为协作枢纽
怎么理解这个“契约”呢?关键在于,要有一个共享的状态对象。你可以定义一个普通的Ja va类,比如叫 TaskQueue,用它来封装需要协作的业务状态——比如任务列表是不是空了,或者计算结果有没有准备好。这个对象身兼三职:它是数据的载体,是同步用的锁,更是线程间通信的“信号灯”。
- 线程A想调用
queue.wait()去等待,前提是它必须先拿到queue这把锁(也就是进入synchronized(queue)块)。一旦调用wait(),它就会释放锁,然后乖乖进入等待队列,直到被唤醒。 - 线程B在修改了共享状态(比如往队列里加了新任务)之后,同样需要在
synchronized(queue)块里,调用queue.notify()或queue.notifyAll()来发出信号。 - 被唤醒的线程(比如刚才的线程A)会重新加入竞争,去抢
queue的锁。抢到之后,它才能从wait()的地方继续执行。这里有个至关重要的细节:醒来后第一件事,应该是重新检查等待条件是否真的满足了。
必须配合 while 循环做条件重检
为什么必须重新检查?因为 wait() 存在“虚假唤醒”的可能性——线程可能因为某些与业务逻辑无关的原因(比如操作系统信号干扰)而被唤醒。所以,绝对不能简单地用 if 判断一次就了事,必须用 while 循环把等待条件包起来:
synchronized (sharedObj) {
while (!conditionMet()) { // 用while,不是if!
sharedObj.wait();
}
// 执行到这里时,conditionMet() 肯定为 true了,可以安全地处理后续逻辑
}
举个典型的例子,在生产者-消费者模型里,消费者线程能行动的前提是“队列非空”。所以,它的等待逻辑必须是 while(!queue.isEmpty()) wait(); —— 即使被唤醒了,也得再瞅一眼队列,确认真的有东西可消费才行。
notify 与 notifyAll 的选择依据
那么,叫醒一个线程,是用 notify() 还是 notifyAll() 呢?这得看场景。
notify()会随机唤醒等待在同一个对象上的一个线程。它适合条件单一、等待方角色明确的场景,比如两个线程严格交替执行。notifyAll()则更“豪爽”,它会唤醒所有正在等待的线程。这种方式更安全、更通用,尤其是在多个线程等待不同条件(比如有的在等“非空”,有的在等“未满”)的复杂场景下。唤醒后,让每个线程自己用while循环去判断是否满足了自己的条件,满足的就继续执行,不满足的继续等待。
对于初学者来说,有个实用的建议:如果不确定该用哪个,那就统一使用 notifyAll()。虽然可能带来一点点性能开销,但它能有效避免因唤醒错对象而导致的死锁风险。当然,如果你能百分之百确定,只有一类线程在等待某个条件,并且你一旦唤醒它,条件肯定满足,那么用 notify() 会更轻量一些。
典型协作模式示例:简单阻塞队列
理论说了这么多,来看一个最经典的“生产一个,消费一个”的协作模式,思路就非常清晰了:
- 生产者线程的行动路线是:获取锁 → 检查队列是否已满(用while循环判断)→ 如果满了就
wait()→ 添加元素 → 调用notifyAll()→ 释放锁。 - 消费者线程的行动路线是:获取锁 → 检查队列是否为空(同样用while循环判断)→ 如果空了就
wait()→ 取出元素 → 调用notifyAll()→ 释放锁。
这个模式里的关键点有两个:一是双方都在修改完共享状态后、离开同步块前调用 notifyAll();二是双方都坚持用 while 循环来重新检查等待条件。把握住这两点,一个基础的线程协作框架就搭建起来了。
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
VSCode设置编辑器边距_调整代码与侧边栏的间距
VSCode 中真正控制编辑器内容区左右留白的是 editor padding 配置项 先明确一个核心概念:VSCode 里并没有一个叫“编辑器与侧边栏间距”的配置。我们常说的那种想让代码离边缘远一点的“边距”,其实指的是编辑器内容区自身的左右内边距。这个功能,完全由 editor padding
如何在VSCode中快速跳转到函数定义、声明或引用位置
如何在VSCode中快速跳转到函数定义、声明或引用位置 为什么 Ctrl+Click 有时跳转失败? 按住 Ctrl(Windows Linux)或 Cmd(macOS)点击函数名就能跳转,这几乎是现代IDE的标配操作。但如果你试过,就会发现它偶尔会“失灵”。问题出在哪?其实,这个看似简单的功能,背
如何清理VSCode中C/C++ Intellisense产生的庞大ipch缓存文件夹释放C盘
如何清理VSCode中C C++ Intellisense产生的庞大ipch缓存文件夹释放C盘 VSCode C C++插件的ipch目录到底占多少空间? 先说一个关键事实:这个ipch文件夹其实并不归VSCode本体管理。它是由微软官方的vscode-cpptools扩展生成的,具体来说,是插件在
Composer提示无法识别的仓库类型_检查repositories配置语法【配置纠错】
“Unrecognized repository type” 错误深度解析与排查指南 遇到 Composer 报出“无法识别的仓库类型”这个错误,很多开发者第一反应是拼写问题。没错,但事情远不止于此。这个错误的本质是,Composer 在 repositories 配置中遇到了一个它完全不认识的 t
如何修改VSCode编辑器右侧的代码缩略图(Minimap)宽度
如何修改VSCode编辑器右侧的代码缩略图(Minimap)宽度 Minimap 宽度由哪个设置控制 如果你觉得VSCode右侧的代码缩略图(Minimap)太宽或太窄,想调整它,那么关键就在于一个设置项: "editor minimap width "。这个设置直接决定了Minimap的视觉宽度。 它
- 日榜
- 周榜
- 月榜
1
2
3
4
5
6
7
8
9
10
相关攻略
2015-03-10 11:25
2015-03-10 11:05
2021-08-04 13:30
2015-03-10 11:22
2015-03-10 12:39
2022-05-16 18:57
2025-05-23 13:43
2025-05-23 14:01
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程
热门话题

