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


Doug Lea在J.U.C包里面写的BUG又被网友发现了文章插图
任务状态是小于等于 COMPLETING 的时候 。
在示例代码中 , 前面的 while 循环中的 isDone 方法已经返回了 true , 说明当前状态肯定不是 NEW 。
那么只剩下个什么东西了?
就只有一个 COMPLETING 状态了 。
小样 , 这不就是监测到了吗?
Doug Lea在J.U.C包里面写的BUG又被网友发现了文章插图
在这段示例代码出来后的第 8 个小时 , David 靓仔又来说话了:
Doug Lea在J.U.C包里面写的BUG又被网友发现了文章插图
他要表达的意思 , 我理解的是这样的:
在 j.u.c 包里面 , 优先检查线程中断状态是很常见的操作 , 因为相对来说 , 会导致线程中断的地方非常的少 。
但是不能因为少 , 我们就不检查了 。
我们还是得对其进行了一个优先检查 , 告知程序当前线程是否发生了中断 , 即是否有继续往下执行的意义 。
但是 , 在这个场景中 , 当前线程中断了 , 但并不能表示 Future 里面的 task 任务的完成情况 。 这是两个不相关的事情 。
即使当前线程中断了 , 但是 task 任务仍然可以继续完成 。 但是执行 get 方法的线程被中断了 , 所以可能会抛出 InterruptedException 。
因为 , 他给出的解决建议是:
可以选择优先返回结果 , 在 awaitDone 方法的循环中把检查中断的代码挪到后面去 。
五天之后 , 之前 BUG 的提交者 Martin 同学又来了:
Doug Lea在J.U.C包里面写的BUG又被网友发现了文章插图
他说他改变主意了 。
改变什么主意了?他之前的主意是什么?
在 Doug 说他是故意这样写的之后 , Martin 说:
It's intentional 。 哦 , 原来是故意的呀 。
那个时候他的主意就是:大佬都说了 , 这样写是考虑过的 , 肯定没有问题 。
现在他的主意是:如果 isDone 方法返回了 true , 那么 get 方法应该明确的返回结果值 , 而不会抛出 IE 异常 。
需要注意的是 , 这个时候对于 BUG 的描述已经发生变化了 。
从“FutureTask.isDone 方法在任务还没有完成的时候就会返回 true”变成了“如果 isDone 方法返回了 true , 那么 get 方法应该明确的返回结果值 , 而不会抛出 IE 异常” 。
然后 David 靓仔给出了一个最简单的解决方案:
Doug Lea在J.U.C包里面写的BUG又被网友发现了文章插图
最简单的解决方案就是先检查状态 , 再检查当前线程是否中断 。
然后 , 这个 BUG 由 Martin 同学进行了修复:
Doug Lea在J.U.C包里面写的BUG又被网友发现了文章插图
修复的代码可以先不看 , 下面一小节我会给大家做个对比 。
他修复的同时还小心翼翼的要求 Doug 祝福他 , 为他站个台 。
最后 , Martin 同学说他已经提交给了 jsr166 , 预计在 JDK 9 版本进行修复 。
出于好奇 , 我在 JDK 的源码中搜索了一下 Martin 同学的名字 , 本以为是个青铜 , 没想到是个王者 , 失敬失敬:
Doug Lea在J.U.C包里面写的BUG又被网友发现了文章插图
代码对比既然说在 JDK 9 中对该 BUG 进行了修复 , 那么带大家对比一下 JDK 9/8 的代码 。
java.util.concurrent.FutureTask#awaitDone:
Doug Lea在J.U.C包里面写的BUG又被网友发现了文章插图
可以看到 , JDK 9 把检查是否中断的操作延后了一步 。