DelayQueue 中的 leader 到底是做什么用的呢?
What exactly is the leader used for in DelayQueue?
我试图理解 java.util.concurrent
中的 DelayQueue
,但 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();
}
}
其次,似乎没有减少不必要的定时等待。根据注释:
This variant of the Leader-Follower pattern (http://www.cs.wustl.edu/~schmidt/POSA/POSA2/) serves to minimize unnecessary timed waiting
我认为这是最小化 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
。
那么,有人可以向我解释一下吗?我在某处有错误的想法吗?
根据源码注释:
It waits only for the next delay to elapse, but other threads await
indefinitely.
领导者不用于minimizing awaitNanos
,它用于避免不必要的唤醒和睡眠。如果让所有线程available.awaitNanos(delay)
都在take
方法中,它们会同时被调用,但只有一个线程能真正从队列中获取元素,其他线程会再次陷入休眠,这是不必要的和资源浪费.
在 Leader-Follower 模式下,领导线程 available.awaitNanos(delay)
,非领导线程 available.await()
。因此领导者将首先醒来并检索一个过期的元素,然后在必要时向另一个等待线程发出信号。这样效率更高。
例子
假设我在队列中有一个元素E
,它会在T
纳秒后失效,并且有两个线程Thread_1
和Thread_2
。
没有leader(你在问题中提供的实现)
Thread_1
调用take
方法,T纳秒后发现E可用,于是调用available.awaitNanos(T)
.
Thread_2
调用take
方法,T纳秒后发现E可用,于是调用available.awaitNanos(T)
.
在 T
纳秒后,Thread_1
醒来并获取元素 E
。 Thread_2
一觉醒来一无所获,只好又睡了。 不需要Thread_2
的唤醒和睡眠。
有领导
Thread_1
调用take
方法,T纳秒后发现E可用,成为leader,调用available.awaitNanos(T)
.
Thread_2
调用take
方法,发现E在T纳秒后可用,但是Thread_2
也注意到已经有leader,所以Thread_2
调用available.await()
.
在 T
纳秒后,Thread_1
醒来并获取元素 E
。 Thread_2
将休眠直到有新元素放入队列。
我想回答 McGar 的最后一条评论,但没有这样做的声誉。
所以我认为领导线程不能保证首先被调用。这里的技巧是当你提供一个新的最早的项目时,你手动设置 leader = null,然后被唤醒的线程将成为新的领导者,无论它是否曾经是领导者。
我试图理解 java.util.concurrent
中的 DelayQueue
,但 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();
}
}
其次,似乎没有减少不必要的定时等待。根据注释:
This variant of the Leader-Follower pattern (http://www.cs.wustl.edu/~schmidt/POSA/POSA2/) serves to minimize unnecessary timed waiting
我认为这是最小化 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
。
那么,有人可以向我解释一下吗?我在某处有错误的想法吗?
根据源码注释:
It waits only for the next delay to elapse, but other threads await indefinitely.
领导者不用于minimizing awaitNanos
,它用于避免不必要的唤醒和睡眠。如果让所有线程available.awaitNanos(delay)
都在take
方法中,它们会同时被调用,但只有一个线程能真正从队列中获取元素,其他线程会再次陷入休眠,这是不必要的和资源浪费.
在 Leader-Follower 模式下,领导线程 available.awaitNanos(delay)
,非领导线程 available.await()
。因此领导者将首先醒来并检索一个过期的元素,然后在必要时向另一个等待线程发出信号。这样效率更高。
例子
假设我在队列中有一个元素E
,它会在T
纳秒后失效,并且有两个线程Thread_1
和Thread_2
。
没有leader(你在问题中提供的实现)
Thread_1
调用take
方法,T纳秒后发现E可用,于是调用available.awaitNanos(T)
.Thread_2
调用take
方法,T纳秒后发现E可用,于是调用available.awaitNanos(T)
.
在 T
纳秒后,Thread_1
醒来并获取元素 E
。 Thread_2
一觉醒来一无所获,只好又睡了。 不需要Thread_2
的唤醒和睡眠。
有领导
Thread_1
调用take
方法,T纳秒后发现E可用,成为leader,调用available.awaitNanos(T)
.Thread_2
调用take
方法,发现E在T纳秒后可用,但是Thread_2
也注意到已经有leader,所以Thread_2
调用available.await()
.
在 T
纳秒后,Thread_1
醒来并获取元素 E
。 Thread_2
将休眠直到有新元素放入队列。
我想回答 McGar 的最后一条评论,但没有这样做的声誉。
所以我认为领导线程不能保证首先被调用。这里的技巧是当你提供一个新的最早的项目时,你手动设置 leader = null,然后被唤醒的线程将成为新的领导者,无论它是否曾经是领导者。