Java多线程wait()阻塞与唤醒逻辑实现正确性咨询
Java wait/notify 并发代码正确性校验
初始等待写法校验
最初的等待代码片段:
owner=Thread.currentThread(); owner.wait();
结论:写法完全错误,核心问题是调用wait()方法前没有持有owner对象的监视器锁,运行时会直接抛出IllegalMonitorStateException。
第一版完整实现问题
用户最初编写的完整等待逻辑:
private Thread owner; public void join() { Thread thread= new Thread(()-> { try { owner= Thread.currentThread(); owner.wait(); } catch (InterruptedException e) { e.printStackTrace(); } }); thread.start(); }
配套唤醒逻辑:
public void wakeUp() { notifyAll(); }
该版本存在以下致命问题:
- 违反wait/notify基础使用规则:所有wait/notify/notifyAll调用必须在持有对应对象监视器锁的同步块/同步方法中执行,上述代码两处调用都没有加同步保护,必然抛出非法监视器状态异常。
- 锁对象不匹配:等待操作是调用
owner实例的wait(),唤醒操作是调用当前实例this的notifyAll(),二者作用在完全不同的对象上,即使补全同步块也无法唤醒等待线程。 - 跨线程可见性无保障:
owner变量没有同步保护也没有volatile修饰,子线程对owner的赋值对执行wakeUp的线程不一定可见,极端场景下会触发空指针异常。 - 方法命名歧义:自定义方法命名为
join(),和Thread类原生的线程等待方法重名,容易造成语义混淆。
累计5次等待后唤醒的更新版代码校验
更新版目标是实现累计5次wait()调用后统一唤醒所有等待线程,代码如下:
private Object mutex = new Object(); private volatile int counter; private boolean condition=false; public void enter() { synchronized (mutex) { counter++; while (!condition) { try { mutex.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } exit(); } } public void exit() { System.out.println("exit()"); } public void checkK() { synchronized (mutex) { if(counter>=5) { mutex.notifyAll(); counter=0; condition=true; } } }
符合规范的部分
- 专门定义了私有专用锁对象
mutex,没有使用Thread、String等可能被外部代码复用的公共对象作为锁,避免意外锁竞争。 - 所有wait/notify操作都在
synchronized (mutex)同步块内执行,持有正确的监视器锁,不会抛出非法监视器状态异常。 - wait条件判断使用
while循环而非if判断,符合Java官方推荐的wait编程范式,可以规避虚假唤醒导致的逻辑错误。
存在的缺陷
- 核心逻辑不可复用:第一次凑够5个等待线程触发唤醒后,
condition变量永远为true,后续所有调用enter()的线程都不会进入等待,会直接执行exit(),无法重复执行「累计5次等待再唤醒」的逻辑,需要在唤醒后合适的时机将condition重置为false。 - 唤醒触发无保障:checkK()方法没有和enter()做联动触发,如果累计等待线程数始终达不到5,且没有外部代码主动调用checkK(),所有等待线程会永久阻塞。
- 中断处理不规范:捕获InterruptedException后仅打印栈轨迹,没有恢复线程中断标记,会丢失中断信号,不符合并发编程最佳实践,正确做法是捕获异常后调用
Thread.currentThread().interrupt()恢复中断状态,或向上抛出异常交由上层处理。 - 多余修饰:
counter变量的所有读写操作都在synchronized同步块保护范围内,synchronized本身已经保证了变量的可见性和原子性,额外加volatile修饰属于冗余代码。
内容的提问来源于stack exchange,提问作者user19427038
相关产品推荐
相关产品推荐

