当前位置: 首页 > news >正文

wait和notify这个为什么要在synchronized代码块中?

一、核心结论先明确

wait()notify()的本质是操作对象的监视器(Monitor),而只有当前线程获取到该对象的 Monitor 锁(也就是进入synchronized代码块 / 方法),才能合法操作这个监视器。如果不在synchronized中调用,会直接抛出IllegalMonitorStateException运行时异常。

二、深层原因:为什么要这样设计?

核心是为了避免线程安全问题(尤其是 “丢失唤醒”),保证 “条件判断 + 等待 / 唤醒” 的原子性。

原因 1:避免 “丢失唤醒”(Lost Wakeup)问题

这是最核心的原因。我们先看一个 “不加 synchronized 会出问题” 的场景:假设存在一个 “生产者 - 消费者” 模型,消费者线程要等生产者生产数据后才能执行:

错误示例(无 synchronized)

// 共享变量:是否有数据 private static boolean hasData = false; private static final Object lock = new Object(); // 消费者线程 Thread consumer = new Thread(() -> { // 步骤1:检查条件 if (!hasData) { // 步骤2:准备等待(此时线程可能被CPU切换) lock.wait(); // 直接抛IllegalMonitorStateException } System.out.println("消费数据"); }); // 生产者线程 Thread producer = new Thread(() -> { hasData = true; lock.notify(); // 直接抛IllegalMonitorStateException System.out.println("生产数据"); });

即使不抛异常,也会出现致命问题:

  1. 消费者线程执行完if (!hasData)(条件为 true),但还没执行wait()时,CPU 切换到生产者线程;
  2. 生产者线程设置hasData=true,并调用notify()(此时没有线程在等待,notify “白发” 了);
  3. 消费者线程回到 CPU,执行wait(),但此时 notify 已经发过了,消费者会永久等待(丢失了这次唤醒)。

加 synchronized 后的正确逻辑

// 消费者线程(正确版) Thread consumer = new Thread(() -> { synchronized (lock) { // 获取锁,保证条件检查+wait原子性 while (!hasData) { // 用while而非if,防止虚假唤醒 lock.wait(); // 释放锁,进入等待 } hasData = false; System.out.println("消费数据"); } }); // 生产者线程(正确版) Thread producer = new Thread(() -> { synchronized (lock) { // 获取锁,保证修改条件+notify原子性 hasData = true; lock.notify(); // 唤醒等待线程 System.out.println("生产数据"); } });

synchronized保证了:

  • 消费者的 “条件检查(!hasData) +wait()” 是原子操作,不会被生产者线程打断;
  • 生产者的 “修改条件(hasData=true) +notify()” 也是原子操作,不会被消费者线程打断;
  • 彻底避免 “丢失唤醒” 问题。
原因 2:操作对象监视器(Monitor)的前提

Java 中每个对象都关联一个 “监视器(Monitor)”,这个监视器是实现同步和线程通信的核心:

  • 调用synchronized (obj)时,线程会尝试获取obj的 Monitor 锁;
  • wait():让当前线程释放 Monitor 锁,并进入该对象的 “等待队列”;
  • notify():从该对象的等待队列中唤醒一个线程,被唤醒的线程需要重新竞争 Monitor 锁。

如果线程没有获取到 Monitor 锁(即不在synchronized中),就没有权限操作这个 Monitor 的等待队列,JVM 会直接抛出IllegalMonitorStateException—— 这是 JVM 的强制规则,本质是保证只有 “持有锁的线程” 才能操作锁的等待队列。

原因 3:防止 “虚假唤醒” 后的逻辑错误

即使加了synchronized,我们也会用while循环检查条件(而非if),这是为了防止 “虚假唤醒”(线程被唤醒后,条件可能已经不满足)。而synchronized保证了循环检查条件时的线程安全:

// 错误:用if,虚假唤醒后直接执行后续逻辑 if (!hasData) { lock.wait(); } // 正确:用while,唤醒后重新检查条件 while (!hasData) { lock.wait(); }

三、关键补充:wait () 的核心特性

很多人误以为wait()是 “暂停线程”,但其实:

  1. wait()调用时,会立即释放当前持有的 Monitor 锁(这是和Thread.sleep()的核心区别 ——sleep 不释放锁);
  2. 线程被 notify () 唤醒后,不会立即执行,而是需要重新竞争Monitor 锁,只有获取到锁后,才能从 wait () 处继续执行;
  3. notifyAll()会唤醒所有等待该锁的线程,这些线程会竞争锁,只有一个能获取到。

总结

  1. 核心目的:避免 “丢失唤醒” 问题,保证 “条件判断 + 等待 / 唤醒” 的原子性,这是多线程通信的线程安全基础;
  2. 底层规则:wait/notify 操作的是对象的 Monitor(监视器),必须先通过 synchronized 获取该 Monitor 锁,否则抛 IllegalMonitorStateException;
  3. 最佳实践:wait () 必须放在 synchronized 代码块中,且用 while 循环检查条件(而非 if),防止虚假唤醒。
http://www.jsqmd.com/news/336554/

相关文章:

  • 学霸同款8个降AI率工具 千笔·降AIGC助手解决论文AI痕迹难题
  • 年底后端招聘市场已经疯掉了。。
  • 当 AI Agent 开始“群魔乱舞“:从 Clawbot 到 Moltbook,一场技术狂欢背后的冷思考
  • 学术导航仪:用书匠策AI解锁期刊论文写作的“星际穿越”
  • 【小程序毕设源码分享】基于springboot+小程序的体育馆综合管理平台的设计与实现(程序+文档+代码讲解+一条龙定制)
  • 学术导航仪:解锁书匠策AI的期刊论文“超维引擎”
  • 2026别错过!AI论文软件 千笔 VS 笔捷Ai,研究生写作新选择!
  • 【小程序毕设源码分享】基于springboot+小程序的居家养老服务的设计与实现(程序+文档+代码讲解+一条龙定制)
  • 2026年江山欧派深度解析:从研发创新维度透视行业领军者的核心驱动力 - 品牌推荐
  • 收藏!京东AI岗薪资碾压多大厂?附京东大模型实习面试题(小白/程序员必看)
  • 【小程序毕设源码分享】基于springboot+小程序的小餐桌管理系统的设计与实现(程序+文档+代码讲解+一条龙定制)
  • 2026冲刺用!AI论文软件 千笔·专业学术智能体 VS 锐智 AI,本科生专属利器!
  • 设计小众书籍推荐工具,输入阅读偏好,推荐小众优质书籍,标注亮点及适合人群,帮读者发现好书,丰富精神世界。
  • 【小程序毕设源码分享】基于springboot+小程序的自驾游平台的设计与实现(程序+文档+代码讲解+一条龙定制)
  • 2026年智能麻将机与安装服务权威推荐:长沙精功包装机械有限公司,战神/KOK/极光系列麻将机批发、安装与技巧全攻略 - 品牌推荐官
  • 【花雕学编程】Arduino BLDC 之动态分配探索区域避免重复路径机器人
  • 2026年预应力混凝土双T板厂家综合推荐:江苏金立方混凝土制品有限公司,高载荷/大跨度/抗腐蚀双T板全系供应,适配工业厂房、仓储物流多场景建筑 - 品牌推荐官
  • Java实习模拟面试 | 百度后端一面:深入拷打实习项目 + 高频八股文连环追问(含手撕链表)
  • task_tick()
  • 从此告别拖延!千笔AI,专科生论文写作神器
  • set_current_state()和schedule()
  • 2026年江山欧派深度解析:从研发创新看木门专家的进阶之路 - 品牌推荐
  • 2026办公室翻新公司推荐:如何挑选专业可靠服务团队 - 品牌排行榜
  • 2026年热处理行业:三大核心趋势重塑未来 - 速递信息
  • 2026年成都短视频代运营公司10强榜单正式发布!动力无限登顶TOP1,实力领跑行业 - 朴素的承诺
  • FDA重新确立NMN膳食补充剂地位 W+端粒塔锚定赛道引领抗衰新纪元 - 速递信息
  • 出墙记录
  • 2026高端酒店设计公司推荐:聚焦品质与创新的行业精选 - 品牌排行榜
  • 元气AI助手功能一览:《国产智能Bot新标杆:你的全能数字工作伙伴》 - PC修复电脑医生
  • 表格识别目前sota