wait() 和 notify() 为什么必须在 synchronized 代码块中使用
                           
天天向上
发布: 2025-07-13 11:36:03

原创
347 人浏览过

wait()notify() 必须在 synchronized 代码块中使用,这是 Java 多线程设计中的一个强制规定,其原因涉及到 Java 对对象监视器(monitor)的使用机制。


1. 背景知识:对象监视器是什么?

Java 中的每一个对象都有一个监视器锁(monitor),也叫“内置锁”或“对象锁”。这个锁可以被 synchronized 获取。

  • wait() 会让当前线程释放监视器锁,并进入等待队列
  • notify() 会让某个等待队列中的线程重新获得锁的竞争权

2. 为什么必须在 synchronized 代码块中?

原因一:wait()notify() 依赖对象的监视器

  • wait()notify()notifyAll() 方法是 Object 类的方法,而不是 Thread
  • 它们必须在当前线程已经持有该对象的监视器锁时调用(也就是在 synchronized(obj) 代码块中),否则抛出 IllegalMonitorStateException 异常。

原因二:保证线程安全和状态一致性

  • 如果在没有同步的情况下调用 wait()notify(),可能会导致:
  • 线程状态混乱(比如一个线程刚进入等待,但还没加入等待队列,另一个线程就调用了 notify(),会错过通知)。
  • 数据竞态(多个线程访问共享数据而没有同步保护)。

3. 强制规定的体现

Object lock = new Object();

lock.wait(); // ❌ 编译通过,运行时抛 IllegalMonitorStateException

必须这样写才合法:

synchronized (lock) {
    lock.wait();  // ✅ 合法,线程当前拥有lock对象的监视器
}

4. 举个完整例子

class WaitNotifyExample {
    private static final Object lock = new Object();

    public static void main(String[] args) {
        Thread waitingThread = new Thread(() -> {
            synchronized (lock) {
                try {
                    System.out.println("线程A等待...");
                    lock.wait();
                    System.out.println("线程A收到通知");
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        });

        Thread notifyingThread = new Thread(() -> {
            synchronized (lock) {
                System.out.println("线程B通知...");
                lock.notify();
            }
        });

        waitingThread.start();
        try { Thread.sleep(100); } catch (InterruptedException e) {}
        notifyingThread.start();
    }
}

5. 总结:为什么要在 synchronized 中调用?

方法是否必须在 synchronized原因
wait()释放锁并进入等待,需要拥有对象锁
notify()通知等待线程,需要拥有对象锁
notifyAll()同上,通知所有等待该对象锁的线程

6. 官方说明与资料


总结口诀

对象监视器,锁内才可操;wait 释放锁,notify 唤人跑。

更多详细内容请关注其他相关文章!

发表回复 0

Your email address will not be published. Required fields are marked *