Doug Lea在J.U.C包里面写的BUG又被网友发现了( 四 )


这句话 , 你用不同的语气可以读出不同的含义 。
我这里倾向于他觉得既然 Doug 当初写这段代码的时候考虑到了这点 , 他分析之后觉得自己这样写是没有问题的 , 就这样写了 。
好嘛 , 前面说 INTERRUPING 不需要特殊处理 , 现在说 COMPLETING 状态是检测不到的 。
那就没得玩了 。
Doug Lea在J.U.C包里面写的BUG又被网友发现了文章插图
事情现在看起来已经是被定性了 , 那就是不需要进行修改 。
但是就在这时 Paul 同学杀了个回马枪 , 应该也是前面的讨论激发了他的思路 , 你不是说检测不出来吗 , 你不是说 get 方法可以获得最终的正确结果吗?
那你看看我这段代码是什么情况:
Doug Lea在J.U.C包里面写的BUG又被网友发现了文章插图
代码是这样的 , 大家可以直接粘贴出来 , 在 JDK 8/9 环境下分别运行一下:
public static void main(String[] args) throws Exception {AtomicReference> a = new AtomicReference<>();Runnable task = () -> {while (true) {FutureTask f = new FutureTask<>(() -> 1);a.set(f);f.run();}};Supplier observe = () -> () -> {while (a.get() == null);int c = 0;int ic = 0;while (true) {c++;FutureTask f = a.get();while (!f.isDone()) {}try {/*Set the interrupt flag of this thread.The future reports it is done but in some cases a call to"get" will result in an underlying call to "awaitDone" ifthe state is observed to be completing."awaitDone" checks if the thread is interrupted and if sothrows an InterruptedException.*/Thread.currentThread().interrupt();f.get();}catch (ExecutionException e) {throw new RuntimeException(e);}catch (InterruptedException e) {ic ++;System.out.println("InterruptedException observed when isDone() == true " + c + " " + ic + " " + Thread.currentThread());}}};CompletableFuture.runAsync(task);Stream.generate(observe::get).limit(Runtime.getRuntime().availableProcessors() - 1).forEach(CompletableFuture::runAsync);Thread.sleep(1000);System.exit(0);}先看一下这段代码的核心逻辑:
Doug Lea在J.U.C包里面写的BUG又被网友发现了文章插图
首先标号为 ① 的地方是两个计数器 , c 代表的是第一个 while 循环的次数 , ic 代表的是抛出 InterruptedException(IE) 的次数 。
标号为 ② 的地方是判断当前任务是否是完成状态 , 如果是 , 则继续往下 。
标号为 ③ 的地方是先中断当前线程 , 然后调用 get 方法获取任务结果 。
标号为 ④ 的地方是如果 get 方法抛出了 IE 异常 , 则在这里进行记录 , 打印日志 。
需要注意的是 , 如果打印日志了 , 说明了一个问题:
前面明明 isDone 方法返回 true 了 , 说明方法执行完成了 。 但是我调用 get 方法的时候却抛出了 IE 异常?
这你怕是有点说不通吧!
JDK 8 的运行结果我给大家截个图 。
Doug Lea在J.U.C包里面写的BUG又被网友发现了文章插图
这个异常是在哪里被抛出来的呢?
awaitDone 方法的入口处 , 就先检查了当前线程是否被中断 , 如果被中断了 , 那么抛出 IE 异常:
Doug Lea在J.U.C包里面写的BUG又被网友发现了文章插图
而代码怎么样才能执行到 awaitDone 方法呢?