我试图理解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();
    }
}

其次,似乎并没有减少不必要的定时等待。根据注解:



我认为这是使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,它用于避免不必要的唤醒和 sleep 。如果让所有线程available.awaitNanos(delay)take方法,它们将被同时调用,但是只有一个线程可以真正从队列中获取元素,其他线程将再次进入休眠状态,这是不必要的并且浪费资源。

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

例子

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

没有领导者(您在问题中提供的实现)

  • 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可用,因此它成为前导者并调用available.awaitNanos(T)
  • Thread_2调用take方法,并在T纳秒后发现E可用,但是Thread_2也注意到已经存在一个领导者,因此Thread_2调用available.await()

  • T纳秒后,Thread_1唤醒并采用E元素。 Thread_2将 hibernate ,直到将新元素放入队列中为止。

    关于java - Leader在DelayQueue中到底用于什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/48493830/

    10-11 18:05