在UltimateQueue中,领导者究竟使用了什么?

问题描述 投票:0回答:1

我试图了解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

那么,有人可以向我解释一下吗?我在某处弄错了吗?

java multithreading concurrency java.util.concurrent blockingqueue
1个回答
1
投票

根据源代码的评论:

它只等待下一个延迟过去,但其他线程无限期地等待。

领导者不用于minimizing awaitNanos,它用于避免不必要的醒来和睡眠。如果你让available.awaitNanos(delay)方法中的所有线程take,它们将同时被调用,但只有一个可以真正从队列中获取元素,其他人将再次陷入沉睡,这是不必要的和资源浪费。

随着Leader-Follower模式,领导者available.awaitNanos(delay),非领导者线程available.await()。因此,领导者将首先唤醒并检索已释放的元素,然后在必要时发出另一个等待线程的信号。这更有效率。

假设我在队列中有一个元素qazxsw poi,它将在qazxsw poi纳秒后过期,并且有两个线程ET

没有领导者(你在问题中提供的实施)

  • Thread_1调用Thread_2方法,并发现E在T纳秒后可用,所以它调用Thread_1
  • take调用available.awaitNanos(T)方法,并发现E在T纳秒后可用,所以它调用Thread_2

take纳秒之后,available.awaitNanos(T)醒来并采取元素TThread_1醒来后什么也得不到,所以它必须再次入睡。 E再次醒来和睡觉是不必要的。

有领导者

  • Thread_2调用Thread_2方法,并发现E在T纳秒后可用,因此它成为领导者并调用Thread_1
  • take调用available.awaitNanos(T)方法,发现E在T纳秒后可用,但Thread_2也注意到已经有一个领导者,所以takeThread_2

Thread_2纳秒之后,available.await()醒来并采取元素TThread_1将睡眠,直到新元素被放入队列中。

© www.soinside.com 2019 - 2024. All rights reserved.