wait/notify 必须配合 synchronized 使用,因它们是对象监视器操作,调用前必须持有锁,否则抛 IllegalMonitorStateException;wait 释放锁并挂起,notify 不释放锁且仅唤醒一个线程;须用 while 循环检查条件防虚假唤醒;BlockingQueue 是更安全的生产者-消费者方案;volatile+CAS 适用于轻量状态通知但不能替代同步;CountDownLatch 和 CyclicBarrier 用于协调等待而非数据传递。

wait/notify 机制必须配合 synchronized 使用
Java 中 wait() 和 notify() 不是线程调度命令,而是对象监视器(monitor)上的操作。调用它们前,当前线程必须已持有该对象的锁,否则会抛出 IllegalMonitorStateException。
- 只能在
synchronized块或方法内调用wait()、notify()、notifyAll() -
wait()会释放锁并挂起线程;notify()不释放锁,只唤醒一个等待线程(不保证唤醒顺序) - 务必用
while而非if检查条件,防止虚假唤醒(spurious wakeup)
synchronized (lock) {
while (!ready) {
lock.wait();
}
// 执行后续逻辑
}
BlockingQueue 是生产者-消费者通信最稳妥的选择
比手写 wait/notify 更安全、更易维护,尤其适合解耦生产与消费逻辑。所有实现类(如 ArrayBlockingQueue、LinkedBlockingQueue)都线程安全,内部已处理好锁和通知。
-
put()在队列满时阻塞,take()在空时阻塞,天然适配“等数据”“等空间”场景 - 避免使用
offer()/poll()的无参版本——它们不阻塞,容易导致忙等 -
LinkedBlockingQueue默认容量为Integer.MAX_VALUE,若生产远快于消费,可能引发 OOM
volatile + CAS 适合轻量状态通知,但不能替代同步
volatile 保证变量的可见性,AtomicBoolean 等原子类提供无锁的 CAS 操作,适用于“单次信号”或“状态翻转”类通信,比如启动/停止标志。
- 不能用于需要“原子复合操作”的场景(如先检查再修改),此时仍需
synchronized或Lock -
volatile boolean shutdown = false;配合循环检查是常见用法,但无法等待某个条件成立(它不阻塞) - 过度依赖
volatile可能掩盖竞态问题,例如两个线程同时执行counter++(读-改-写三步),即使counter是volatile也不安全
CountDownLatch 和 CyclicBarrier 解决的是“协调等待”,不是数据传递
它们不传输值,只用来控制线程执行节奏。误用会导致语义混乱:比如想让线程 A 等待线程 B 计算出结果,却用了 CountDownLatch,结果发现没有地方存那个结果。
立即学习“Java免费学习笔记(深入)”;
-
CountDownLatch是一次性门闩,适合“主线程等 N 个任务完成”;CyclicBarrier可重用,适合多轮协作(如分治计算每轮同步) - 若需传递结果,应组合使用:用
CountDownLatch同步时机,用AtomicReference或共享对象存放结果 -
CyclicBarrier的barrierAction在所有线程到达后、释放前执行,可用于汇总数据,但要注意该动作也受屏障锁保护









