2026/4/6 3:59:39
网站建设
项目流程
网站建设的 几点,国外html5模板网站,wordpress wdcp 伪静态,织梦网站防止注入一、核心结论先明确wait()和notify()的本质是操作对象的监视器#xff08;Monitor#xff09;#xff0c;而只有当前线程获取到该对象的 Monitor 锁#xff08;也就是进入synchronized代码块 / 方法#xff09;#xff0c;才能合法操作这个监视器。如果不在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(生产数据); });即使不抛异常也会出现致命问题消费者线程执行完if (!hasData)条件为 true但还没执行wait()时CPU 切换到生产者线程生产者线程设置hasDatatrue并调用notify()此时没有线程在等待notify “白发” 了消费者线程回到 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()” 是原子操作不会被生产者线程打断生产者的 “修改条件hasDatatrue 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()是 “暂停线程”但其实wait()调用时会立即释放当前持有的 Monitor 锁这是和Thread.sleep()的核心区别 ——sleep 不释放锁线程被 notify () 唤醒后不会立即执行而是需要重新竞争Monitor 锁只有获取到锁后才能从 wait () 处继续执行notifyAll()会唤醒所有等待该锁的线程这些线程会竞争锁只有一个能获取到。总结核心目的避免 “丢失唤醒” 问题保证 “条件判断 等待 / 唤醒” 的原子性这是多线程通信的线程安全基础底层规则wait/notify 操作的是对象的 Monitor监视器必须先通过 synchronized 获取该 Monitor 锁否则抛 IllegalMonitorStateException最佳实践wait () 必须放在 synchronized 代码块中且用 while 循环检查条件而非 if防止虚假唤醒。