wait()和notify()是java中用于线程协作的同步机制,必须在synchronized块中调用且锁对象一致,需用while循环避免虚假唤醒,典型应用为生产者-消费者模型。

Java 中 Object 类的 wait() 和 notify() 是实现线程间协作的基础机制,但必须在同步上下文中使用,否则会抛出 IllegalMonitorStateException。它们不是用来“控制线程执行顺序”的万能工具,而是用于协调多个线程对共享资源的访问,典型场景是生产者-消费者模型。
wait() 和 notify() 的基本规则
wait() 让当前线程释放锁并进入等待队列;notify() 唤醒**等待队列中的一个**线程(不保证是哪个);notifyAll() 唤醒所有等待线程。关键点:
- 必须在
synchronized方法或代码块中调用,且锁对象必须是调用wait/notify的对象本身 - 调用
wait()后,线程释放锁并挂起;被唤醒后需重新竞争锁,获得锁后才从wait()返回 -
wait()应始终在 while 循环中调用,避免虚假唤醒(spurious wakeup) -
notify()不会释放当前锁,唤醒只是“发信号”,被唤醒线程仍需等当前线程退出同步块后才能继续
正确使用 wait/notify 的典型结构
以共享缓冲区为例,两个线程交替向其中添加/读取数据:
class SharedBuffer {
private String data = null;
public synchronized void put(String value) throws InterruptedException {
while (data != null) { // 条件不满足时等待
wait();
}
data = value;
notify(); // 唤醒可能在 get() 中等待的线程
}
public synchronized String get() throws InterruptedException {
while (data == null) { // 条件不满足时等待
wait();
}
String result = data;
data = null;
notify(); // 唤醒可能在 put() 中等待的线程
return result;
}
}
注意:用 while 而非 if,因为线程被唤醒后条件可能已再次改变(如多个消费者同时被唤醒,只有一个能取走数据)。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
常见错误与规避方式
新手容易踩的坑:
- 在非同步上下文中调用
wait/notify→ 立即抛异常 - 用错锁对象:比如在
synchronized(obj1)块里调用obj2.wait()→ 抛异常 - 用
if判断条件 → 可能跳过检查,导致逻辑错误或死锁 - 只用
notify()却有多个等待线程 → 其他线程永远无法被唤醒,造成假死 - 忘记处理
InterruptedException→ 中断信号被吞,线程无法响应中断
替代方案建议(现代 Java 更推荐)
wait/notify 底层灵活但易出错。JDK 5+ 提供了更安全、语义更清晰的工具:
-
java.util.concurrent.locks.Condition:配合ReentrantLock使用,支持多个等待队列、精确唤醒 -
BlockingQueue(如ArrayBlockingQueue):封装了线程安全的存取逻辑,直接调用put()/take()即可阻塞等待 -
Semaphore、CountDownLatch、CyclicBarrier:针对不同协作模式提供专用语义
除非需要深度定制或维护老代码,否则优先选用这些高级并发工具。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










