虚假唤醒
在 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的一个坑
好好的说着 JDK 的 FutureTask 呢,怎么突然转弯到 Netty 上了?
因为 Netty 里面,其核心的 Future 接口实现中,犯了一个基本的逻辑错误,在实现 cancel 和 isDone 方法时违反了 JDK 的约定。
这是一个让 Netty 作者也感到惊讶的错误。
先看看 JDK Future 接口中,对于 cancel 方法的说明:
https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/Future.html
文档的方法说明上说:如果调用了 cancel 方法,那么再调用 isDone 将永远返回 true。
看一下这个测试代码:
可以看到,在调用了 cancel 方法后,再次调用 isDone 方法,返回的确实 false。
这个点我是很久之前在知乎的这篇文章上看到的,和本文讨论的内容有一点点相关度,我就又翻了出来,多说了一嘴。
有兴趣的可以看看:《一个让Netty作者也感到惊讶的错误》
好啦,才疏学浅,难免会有纰漏,如果你发现了错误的地方,可以在留言区提出来,我对其加以修改。
感谢您的阅读,我坚持原创,十分欢迎并感谢您的关注。