Doug Lea在J.U.C包里面写的BUG又被网友发现了( 六 )
代码修改为这样后 , 把之前的那段示例代码放到 JDK 9 上面跑一下 , 你会惊奇的发现 , 没有抛出异常了 。
因为源码里面判断 COMPLETING 的操作在判断线程中断标识之前:
文章插图
我想就不需要我再过多解释了吧 。
然后多说一句 JDK 9 现在的 FutureTask#awaitDone 里面有这样的一行注释:
文章插图
它说:isDone 方法已经告诉使用者任务已经完成了 , 那么调用 get 方法的时候我们就不应该什么都不返回或者抛出一个 IE 异常 。
这行注释想要表达的东西 , 就是上面一小节的 BUG 里面我们在讨论的事情 。 写这行注释的人 , 就是 Martin 同学 。
当我了解了这个 BUG 的来龙去脉之后 , 又突然间在 JDK 9 的源码里面看到这个注释的时候 , 有一种很神奇的感觉 。
就是一种源码说:you feel me?
我马上心领神会:I get you 。
挺好 。
文章插图
虚假唤醒在 JDK 9 的注释里面还有这个词汇:
文章插图
spurious wakeup , 虚假唤醒 。
如果你之前不知道这个东西的存在 , 那么恭喜你 , 又 get 到了一个你基本上用不到的知识点 。
除非你自己需要在代码中用到 wait、notify 这样的方法 。
哦 , 也不对 , 面试的时候可能会用到 。
“虚假唤醒”是怎么一回事呢 , 我给你看个例子:
java.lang.Thread#join(long) 方法:
文章插图
这里为什么要用 while 循环 , 而不是直接用 if 呢?
因为循环体内有调用 wait 方法 。
为什么调用了 wait 方法就必须用 while 循环呢?
别问 , 问就是防止虚假唤醒 。
看一下 wait 方法的 javadoc:
文章插图
一个线程能在没有被通知、中断或超时的情况下唤醒 , 也即所谓的“虚假唤醒” , 虽然这点在实践中很少发生 , 但是程序应该循环检测导致线程唤醒的条件 , 并在条件不满足的情况下继续等待 , 来防止虚假唤醒 。
所以 , 建议写法是这样的:
文章插图
在 join 方法中 , isAlive 方法就是这里的 condition does not hold 。
在《Effective Java》一书中也有提到“虚假唤醒”的地方:
文章插图
书中的建议是:没有理由在新开发的代码中使用 wait、notify 方法 , 即使有 , 也应该是极少了 , 请多使用并发工具类 。
再送你一个面试题:为什么 wait 方法必须放在 while 循环体内执行?
现在你能回答的上来这个问题了吧 。
关于“虚假唤醒”就说这么多 , 有兴趣的同学可以再去仔细了解一下 。
Netty的一个BUG好好的说着 JDK 的 FutureTask 呢 , 怎么突然转弯到 Netty 上了?
因为 Netty 里面 , 其核心的 Future 接口实现中 , 犯了一个基本的逻辑错误 , 在实现 cancel 和 isDone 方法时违反了 JDK 的约定 。
这是一个让 Netty 作者也感到惊讶的错误 。
先看看 JDK Future 接口中 , 对于 cancel 方法的说明:
推荐阅读
- Clearbot:一款能自动在水上追踪收集垃圾的机器人
- Clearfind:帮企业合理规划软件投入 寻找最适合方案
- 齿间洁净 时刻自信 Oclean W1冲牙器抢先体验
- 冲牙器|Oclean W1便携式智能空气动力冲牙器体验:极致便携的小钢炮,给足了让你带上它旅行的理由
- 极致静音体验 Oclean Air2电动牙刷评测
- Google推出XS-Leaks Wiki 普及有关跨站泄露的网络安全知识
- DeepLearningwithPyTorch-1.0 简介
- 猫咪高冷不让抱 Leader空调Home一键秒变“粘人精”
- 乐谈科技|W1智能冲牙器评测:空气动力值得一试,体积最小的Oclean
- 小熊在线|Oclean Air 2超静音电动牙刷图赏,静享私密时刻