JDK 中的 DelayQueue 源码阅读
JUC 中的延时队列 DelayQueue 的源码很简洁 ,值得读一下。
顺便调查了几个问题:
- 为啥作者总是喜欢在使用对象属性 lock 的时候,在方法中先赋予一个 final 的变量?
- Leader-Follower 模式是个啥?
- 如果给 DelayQueue 做单元测试,怎么去覆盖到各种竞争条件?
为啥作者总是喜欢在使用对象属性 lock 的时候,在方法中先赋予一个 final 的变量?
像以下这种,作者总是喜欢先把 this.lock 赋给一个局部的临时变量后再使用,感觉很奇怪。
final ReentrantLock lock = new ReentrantLock(); public void putLast(E e) throws InterruptedException { final ReentrantLock lock = this.lock; lock.lock(); try { // do stuff } finally { lock.unlock(); } }
先用关键字 why delayqueue create local variable for lock 谷歌一下,前两条就给出了答案,Martin Buchholz 在2010年的一封邮件解释了
Martin Buchholz martinrb at google.com
It's a coding style made popular by Doug Lea.
It's an extreme optimization that probably isn't necessary;
you can expect the JIT to make the same optimizations.
(you can try to check the machine code yourself!)
Nevertheless, copying to locals produces the smallest
bytecode, and for low-level code it's nice to write code
that's a little closer to the machine.Also, optimizations of finals (can cache even across volatile
reads) could be better. John Rose is working on that.For some algorithms in j.u.c,
copying to a local is necessary for correctness.
然后我查看了一下字节码,如下图,没有赋值本地变量的,在 lock 和 unlock 的地方,多了一次 getfield 调用。但是从整体来看 ,并没有降低字节码的量 ,反而是多了2行。因此 ,我们可以更多的当做是 Doug Lea 所使用的一种代码风格而已 。更多的一些说明可以参考 Stackoverflow 上的一些讨论。
Leader-Follower 模式是个啥?
代码中的注释说得很清楚,leader 的使用是应用了 Leader-Follower 模式的一个变种,是为了最小化等待。
如果不使用 leader 来实现的话,就会发现从队列中获取到时元素,都会是等待 delay,然后都去抢,造成激烈竞争,浪费 CPU 计算,因为只有一个会抢到到时元素,其它都抢不到,然后进入下一轮休眠竞争。使用了 leader,则只有 leader 会醒来获取到时元素,其它线程则是无尽等待直到有人拿到超时元素后唤起其中一个成为新的 leader。
如果给 DelayQueue 做单元测试,怎么去覆盖到各种竞争条件?
就是需要构造以下竞争场景:
- 队列中只有一个元素,仍未到时,此时3个线程同时获取,1个休眠指定时间获取到,另外2个无尽等待;
- 在1的基础上 ,超时没有完成之前,向列表中添加一个新的元素,新的元素延时在老的元素延时之后;
- 与2类似,只是新的元素延时在老的元素延时之前;
- signal 唤起 leader 休眠 ;
- signal 唤起 follower 的休眠 ;
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论