我试图了解DelayQueue
中的java.util.concurrent
,但是leader
让我很困惑。
首先,我们可以实现一个没有leader
的DelayQueue,如下所示:
public boolean offer(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
q.offer(e);
if (q.peek() == e) {
available.signal();
}
return true;
} finally {
lock.unlock();
}
}
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
for (;;) {
E first = q.peek();
if (first == null) {
available.await();
} else {
long delay = first.getDelay(TimeUnit.NANOSECONDS);
if (delay <= 0) {
return q.poll();
} else {
available.awaitNanos(delay);
}
}
}
} finally {
lock.unlock();
}
}
其次,似乎不会减少不必要的定时等待。根据注释:
Leader-Follower模式(http://www.cs.wustl.edu/~schmidt/POSA/POSA2/)的这种变体用于最小化不必要的定时等待
我把它当作最小化awaitNanos
(使用await
而不是awaitNanos
),但我真的怀疑。如果新元素不是队列的头部,则不会发出任何线程信号。 (参见下面的offer
方法)
if (q.peek() == e) {
leader = null; // set leader to null
available.signal();
}
因此,当新元素是头部时,它才会有所不同。但在这种情况下,leader
将被设置为null
,并且发出信号的线程将不会这样(take
方法):
else if (leader != null)
available.await();
线程总是会做awaitNanos
。
那么,有人可以向我解释一下吗?我在某处弄错了吗?
根据源代码的评论:
它只等待下一个延迟过去,但其他线程无限期地等待。
领导者不用于minimizing awaitNanos
,它用于避免不必要的醒来和睡眠。如果你让available.awaitNanos(delay)
方法中的所有线程take
,它们将同时被调用,但只有一个可以真正从队列中获取元素,其他人将再次陷入沉睡,这是不必要的和资源浪费。
随着Leader-Follower模式,领导者available.awaitNanos(delay)
,非领导者线程available.await()
。因此,领导者将首先唤醒并检索已释放的元素,然后在必要时发出另一个等待线程的信号。这更有效率。
假设我在队列中有一个元素qazxsw poi,它将在qazxsw poi纳秒后过期,并且有两个线程E
和T
。
没有领导者(你在问题中提供的实施)
Thread_1
调用Thread_2
方法,并发现E在T纳秒后可用,所以它调用Thread_1
。take
调用available.awaitNanos(T)
方法,并发现E在T纳秒后可用,所以它调用Thread_2
。在take
纳秒之后,available.awaitNanos(T)
醒来并采取元素T
。 Thread_1
醒来后什么也得不到,所以它必须再次入睡。 E
再次醒来和睡觉是不必要的。
有领导者
Thread_2
调用Thread_2
方法,并发现E在T纳秒后可用,因此它成为领导者并调用Thread_1
。take
调用available.awaitNanos(T)
方法,发现E在T纳秒后可用,但Thread_2
也注意到已经有一个领导者,所以take
称Thread_2
。在Thread_2
纳秒之后,available.await()
醒来并采取元素T
。 Thread_1
将睡眠,直到新元素被放入队列中。