wait/notify 必须在 synchronized 块中调用,否则抛 IllegalMonitorStateException;唤醒需同锁下 notifyAll() 更安全;wait 前须用 while 检查条件防虚假唤醒;volatile 不保证原子性,复合操作仍需同步;ConcurrentHashMap 迭代器弱一致;ReentrantLock 的 Condition 支持多等待队列。

wait/notify 必须在 synchronized 块中调用
直接调用 wait() 或 notify() 会抛出 IllegalMonitorStateException,因为 JVM 要求当前线程必须持有对象的监视器锁。这不是可选约定,而是强制语义。
- 必须用
synchronized(obj) { obj.wait(); },不能只写obj.wait(); - 唤醒方也必须在同一个锁保护下调用
notify()或notifyAll() - 推荐始终使用
notifyAll():多个等待线程共用同一条件时,notify()可能唤醒错误线程导致假死 - wait 前必须用 while 循环检查条件,不能用 if:防止虚假唤醒(spurious wakeup)
synchronized (lock) {
while (!ready) {
lock.wait();
}
// 处理就绪逻辑
}
volatile 无法替代 synchronized 实现原子写-读组合
volatile 只保证可见性和禁止重排序,不提供原子性。对复合操作(如 count++)无效,仍需同步机制。
-
volatile boolean flag适合做状态开关(如停止信号),但不能用于计数器、引用替换+校验等场景 -
volatile字段的写操作对其他线程立即可见,但“写后立刻读到最新值”不等于“多个 volatile 操作构成原子序列” - 若需原子更新,优先考虑
AtomicInteger、AtomicReference等类,它们底层基于 CAS + volatile
private volatile boolean shutdownRequested = false; // ✅ 安全:单次写,其他线程读取即刻可见 shutdownRequested = true; private volatile int counter = 0; counter++; // ❌ 非原子:读-改-写三步,可能丢失更新
ConcurrentHashMap 的弱一致性迭代器
ConcurrentHashMap 的 keySet()、values()、entrySet() 返回的迭代器是弱一致(weakly consistent),不抛 ConcurrentModificationException,但也不保证反映某一时刻的快照。
一套傻瓜式的建站程序,由前台购物、后台管理、在线支付三部分组成介绍说明:1.注册与否均可购物(同类程序大多要求注册才能购物),方便了那些懒得注册的客户。降低用户使用门槛,自然可抓住更多潜在商机。2.会员等级和折扣功能。管理员可方便的为会员设置不同等级,不同等级的员会可享受不同的购物折扣。3.站内短信、留言发布,沟通无极限。会员和游客均可发送短信和留言。4.完美融合在线支付功能,无需编程、无需修改源
- 迭代过程中允许并发修改,不会阻塞也不会崩溃
- 可能跳过刚插入的元素,也可能重复返回已删除元素(概率低,但存在)
- 不支持
Iterator.remove()—— 会抛UnsupportedOperationException - 若需强一致性遍历,应先
new ArrayList(map.keySet())复制,再遍历副本(注意内存与时效权衡)
ReentrantLock 的 newCondition() 比 Object 的 wait/notify 更灵活
ReentrantLock 支持创建多个 Condition 实例,实现多条件等待(比如“缓冲区非空”和“缓冲区非满”可分别 await),而 Object.wait() 只有一个隐式等待队列。
立即学习“Java免费学习笔记(深入)”;
- 每个
Condition对应独立的等待队列,signal()只唤醒该条件上的线程 - 必须在持有对应锁的前提下调用
await()/signal(),否则抛IllegalMonitorStateException - 使用完记得
lock.unlock(),建议用 try-finally 包裹
Lock lock = new ReentrantLock();
Condition notEmpty = lock.newCondition();
Condition notFull = lock.newCondition();
lock.lock();
try {
while (queue.size() == 0) {
notEmpty.await();
}
// 取元素...
} finally {
lock.unlock();
}
实际写业务逻辑时,最容易被忽略的是:**条件变量的守卫逻辑必须与唤醒逻辑严格对称,且所有共享状态变更必须在同一个锁下完成**。少一个 synchronized、漏一次 notifyAll()、或把条件判断写在锁外,都会让线程卡死或数据错乱。










