您当前的位置:首页 > 计算机 > 编程开发 > Java

JDK 中的 DelayQueue 源码阅读

时间:12-14来源:作者:点击数:

JUC 中的延时队列 DelayQueue 的源码( github /ZenOfAutumn/jdk8/blob/master/java/util/concurrent/DelayQueue.java)很简洁 ,值得读一下。

顺便调查了几个问题:

  1. 为啥作者总是喜欢在使用对象属性 lock 的时候,在方法中先赋予一个 final 的变量?
  2. Leader-Follower 模式是个啥?
  3. 如果给 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年的一封邮件( mail.openjdk.java 网络网/pipermail/core-libs-dev/2010-May/004165.html)解释了

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 上的一些讨论( stackoverflow 商业网/questions/8019831/java-lock-variable-assignment-before-use-why)。

Leader-Follower 模式是个啥?

代码中的注释说得很清楚,leader 的使用是应用了 Leader-Follower 模式的一个变种,是为了最小化等待。

如果不使用 leader 来实现的话,就会发现从队列中获取到时元素,都会是等待 delay,然后都去抢,造成激烈竞争,浪费 CPU 计算,因为只有一个会抢到到时元素,其它都抢不到,然后进入下一轮休眠竞争。使用了 leader,则只有 leader 会醒来获取到时元素,其它线程则是无尽等待直到有人拿到超时元素后唤起其中一个成为新的 leader。

如果给 DelayQueue 做单元测试,怎么去覆盖到各种竞争条件?

就是需要构造以下竞争场景:

  1. 队列中只有一个元素,仍未到时,此时3个线程同时获取,1个休眠指定时间获取到,另外2个无尽等待;
  2. 在1的基础上 ,超时没有完成之前,向列表中添加一个新的元素,新的元素延时在老的元素延时之后;
  3. 与2类似,只是新的元素延时在老的元素延时之前;
  4. signal 唤起 leader 休眠 ;
  5. signal 唤起 follower 的休眠 ;
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门
本栏推荐