CompletableFuture.supplyAsync抛出IllegalMonitorStateException问题
结论
这个报错是预期行为,你的代码存在明确的写法疏漏。
错误原因
- 核心异常来源是对
Object.wait()方法的错误使用
所有Java对象都继承了wait()、notify()、notifyAll()这三个方法,它们属于对象内置监视器机制的组成部分,调用wait()的硬性前提是当前线程必须持有该对象的synchronized监视器锁,未持有锁直接调用就会固定抛出IllegalMonitorStateException,和CompletableFuture任务是否完成没有任何关系。
你看到输出里已经打印了Alarm:911,是因为异步任务执行速度很快,在主线程走到wait调用前就已经完成、触发了回调,但这不会消除wait方法本身的用法错误。 - 混淆了API的适用场景
wait()根本不是用来等待CompletableFuture任务完成的API,就算你给wait外层加了synchronized锁,也达不到预期效果——CompletableFuture任务完成时不会主动调用notify/notifyAll唤醒等待线程,你会直接阻塞住无法正常唤醒。 - 存在隐藏的空指针风险
你在whenComplete回调里没有判断error是否为null就直接调用error.printStackTrace(),当任务正常执行完成(比如你当前返回911的场景)时,error参数是null,这行代码会在异步线程中抛出空指针异常,只是因为你没有持有whenComplete返回的新CompletableFuture对象,异常没有被主线程感知到而已。
修正方案
等待CompletableFuture完成要使用它自带的阻塞API,同时修复回调的空指针问题:
- 要获取任务返回值就用
get()方法,它会阻塞直到任务完成,返回执行结果,需要处理受检异常; - 不需要返回值可以用
join()方法,它同样会阻塞等待,抛出的是非受检异常,不需要显式声明捕获。
修正后的可运行代码:
public static void main(String[] args) throws Exception { CompletableFuture<Integer> future = CompletableFuture.supplyAsync( () -> { return 911; }); future.whenComplete( (result, error) -> { System.out.println("Alarm:" + result); // 判空避免空指针 if (error != null) { error.printStackTrace(); } } ); // 替换wait(),等待异步任务完成 future.get(); }
运行这段代码就只会打印Alarm:911,不会有任何异常抛出。
内容的提问来源于stack exchange,提问作者Troskyvs
相关产品推荐
相关产品推荐

