JUC 中的延时队列 DelayQueue 的源码( github /ZenOfAutumn/jdk8/blob/master/java/util/concurrent/DelayQueue.java)很简洁 ,值得读一下。
顺便调查了几个问题:
像以下这种,作者总是喜欢先把 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 的使用是应用了 Leader-Follower 模式的一个变种,是为了最小化等待。


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

