Java多线程中如何等待消息(含超时)?求wait/notify优化方案
异步消息等待逻辑的优化实现
你的现有轮询方案存在明显缺陷:
- 轮询间隔固定,要么响应不及时(间隔过大),要么浪费CPU资源(间隔过小)
- 代码未实现真正的超时逻辑,会无限循环直到消息到来
- 线程安全隐患:
message的赋值和messageReceived的更新并非原子操作,可能出现线程看到messageReceived=true但message还未完成赋值的情况;重置messageReceived的操作也无同步保护,易引发并发问题
使用wait()/notify()的最优实现
基于wait/notify的方案可避免轮询的性能损耗,同时精准处理超时,且保证线程安全:
class SignalReceiver { private String message; private boolean messageReceived; // 同步块内保证可见性,无需AtomicBoolean // 接收消息的方法必须同步,保证操作原子性 synchronized void receive(String message) { this.message = message; this.messageReceived = true; notifyAll(); // 唤醒所有等待的线程 } /** * 等待消息到来或超时 * @param timeout 超时时间,单位毫秒 * @return 收到的消息,超时则返回null * @throws InterruptedException 线程被中断时抛出 */ synchronized String waitTillMessageReceived(long timeout) throws InterruptedException { long endTime = System.currentTimeMillis() + timeout; long remainingTime = timeout; // 循环判断,处理虚假唤醒 while (!messageReceived && remainingTime > 0) { wait(remainingTime); // 等待指定时长,或被notify唤醒 remainingTime = endTime - System.currentTimeMillis(); } // 处理结果:收到消息则重置状态并返回,超时返回null if (messageReceived) { String result = this.message; this.message = null; this.messageReceived = false; return result; } else { return null; } } }
方案优势说明
- 性能更优:线程无消息时进入等待状态,不占用CPU资源,消息到来时立即被唤醒
- 精准超时:通过计算剩余等待时间,保证超时逻辑的准确性
- 线程安全:所有访问共享变量的操作都在
synchronized块内,保证原子性和可见性 - 处理虚假唤醒:使用
while循环而非if判断条件,避免线程被虚假唤醒后错误判定消息已到达
其他可选方案(扩展)
如果不局限于wait/notify,Java并发包提供了更易用的工具:
BlockingQueue:直接使用LinkedBlockingQueue,调用poll(timeout, TimeUnit.MILLISECONDS)即可实现等待消息或超时,代码更简洁CompletableFuture:适合异步场景,接收消息时调用complete(),等待方调用get(timeout, TimeUnit.MILLISECONDS)CountDownLatch:初始化计数为1,接收消息时countDown(),等待方调用await(timeout, TimeUnit.MILLISECONDS)
内容的提问来源于stack exchange,提问作者Tejas jain
相关产品推荐
相关产品推荐

