Hablemos de la clase de implementación de BlockingQueue java.util.concurrent.DelayQueue (análisis de código fuente JDK1.8)

Análisis del código fuente de DelayQueue



Prefacio

DelayQueue de clase pública amplía los
implementos de AbstractQueue BlockingQueue {

AbstractQueue: El esqueleto básico de Queue.
BlockingQueue: Interfaz de cola de bloqueo.
Delayed: Interfaz de retardo, que contiene el método getDelayed para devolver el tiempo de retardo restante del objeto. Esta interfaz implementa Comparable


Sugerencia: El siguiente es el contenido de este artículo, los siguientes casos son para referencia

Uno, parte del código fuente de DelayQueue

1. Constructor

//无参空构造函数
public DelayQueue() {
    
    }

//带参构造函数
public DelayQueue(Collection<? extends E> c) {
    
    
    this.addAll(c);
}

//加入一个集合的元素到该队列中去
public boolean addAll(Collection<? extends E> c) {
    
    
    if (c == null) //不能加入空元素
        throw new NullPointerException(); //空指针异常
    if (c == this)
        throw new IllegalArgumentException(); //非法算术异常(不能自己加自己)
    boolean modified = false;
    for (E e : c) //遍历集合元素添加到队列中去
        if (add(e)) //调用了本类的offer方法,成功时返回true
            modified = true;
    return modified; //只有队列被修改并且没有抛出异常的情况下将会返回true
}

2. Variables de miembros

//该延迟队列底层是用的一个优先级队列来存储数据的
private final PriorityQueue<E> q = new PriorityQueue<E>();

//全局锁
private final transient ReentrantLock lock = new ReentrantLock();

//当队列头部有新元素可用或新线程可能需要成为leader时发出的条件。
private final Condition available = lock.newCondition();

///

//关于Condition中线程的挂起和唤醒的一些方法的使用
//Condition的创建
ReentrantLock lock = new ReentrantLock();  //首先需要一把锁
Condition condition = lock.newCondition();  //通过该锁实例对象创建Condition

//该方法阻塞当前线程直到被其他线程唤醒或者该线程被中断
condition.await();
//该方法阻塞当前线程直到被其他线程唤醒或者该线程被中断或者超过指定long时间(时间单位为纳秒)
condition.awaitNanos(long);
//唤醒阻塞线程中的一个
condition.signal();
//唤醒阻塞的所有线程
condition.signalAll();
//执行上面方法时必须先获得lock锁(lock.lock()),否则将抛出异常java.lang.IllegalMonitorStateException。

//当一个线程要从队列中取元素时,队首的元素可能剩余延迟时间>0此时,该线程需要
//等待剩余延迟时间然后才可以等待其他线程将其唤醒,此时其他线程也可从队列中获取元素,发现leader不为null的时候,其他线程将会直接阻塞等待唤醒
private Thread leader = null;

3. Método principal

Únete al equipo

método de oferta

public boolean offer(E e) {
    
    
    final ReentrantLock lock = this.lock; //获取全局锁
    lock.lock(); //加锁
    try {
    
    
        q.offer(e); //向优先级队列加入元素e
        //如果加入的元素是队列中延迟时间最小的(优先级最高的)该元素则位于队首
        if (q.peek() == e) {
    
    
            leader = null; //leader线程所指向线程将于其他线程有相等的竞争
            available.signal(); //唤醒其他等待出队操作的线程(随机唤醒一个)
        }
        return true; //入队成功返回true
    } finally {
    
    
        lock.unlock(); //释放锁
    }
}

//该方法与上面方法相同
public boolean offer(E e, long timeout, TimeUnit unit) {
    
    
    return offer(e);
}

//该方法用于获得队首元素(加锁了)
public E peek() {
    
    
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
    
    
        return q.peek();
    } finally {
    
    
        lock.unlock();
    }
}

//与offer方法相同
public void put(E e) {
    
    
    offer(e);
}

Dejar el equipo

public E poll() {
    
    
    final ReentrantLock lock = this.lock; //全局锁
    lock.lock();  //加锁
    try {
    
    
        E first = q.peek(); //获得优先级队列中的队首元素(不移除该元素)
        if (first == null || first.getDelay(NANOSECONDS) > 0)
            return null;//队列为null,或有剩余延迟时间,直接返回空
        else
            return q.poll(); //出队
    } finally {
    
    
        lock.unlock(); //释放锁
    }
}

public E poll(long timeout, TimeUnit unit) throws InterruptedException {
    
    
    long nanos = unit.toNanos(timeout); //超时时间
    final ReentrantLock lock = this.lock; //获取全局锁
    lock.lockInterruptibly(); //加锁线程中断时该锁可被打破释放
    try {
    
    
        for (;;) {
    
    
            E first = q.peek(); //返回队首元素
            if (first == null) {
    
     //队首为null则队列为空
                if (nanos <= 0) //等待时间<=0直接返回null
                    return null;
                else  //否则该线程阻塞nanos时间后自动被唤醒或中途被其他线程唤醒
                    nanos = available.awaitNanos(nanos);
            } else {
    
     //队列非空的情况
                long delay = first.getDelay(NANOSECONDS); //获取队首元素剩余延迟时间
                if (delay <= 0) //剩余延迟时间<= 0
                    return q.poll(); //直接出队poll过程 //a
                if (nanos <= 0) //剩余延迟时间>0并且超时时间 <= 0的情况下(该线程不等待)
                    return null; //直接返回null  //b
                first = null; // don't retain ref while waiting
                //1.这里当超时时间小于延迟时间时,该线程仍然等待nanos时间,因
				//为此时他释放了自己锁持有的锁资源,其他线程可以进行入队操作,
				//且队首元素可能被改变
				//2.如果当超时时间大于等于延迟时间时,并且leader不为null(说明
				//也有线程在进行出队操作),将会等待nanos时间
                if (nanos < delay || leader != null)
                    nanos = available.awaitNanos(nanos);
                else {
    
     //3. 没有其他线程在进行入队操作时
                    Thread thisThread = Thread.currentThread(); //获取当前线程
                    leader = thisThread; //设置成员变量leader为当前线程
                    try {
    
    
                        long timeLeft = available.awaitNanos(delay); //等待指定延迟时间
						//这里等待指定延迟时间后为什么不直接去得队首元素
						//和上面原因类似,此时其他线程可能进行入队或出队操作改变了队首元素
                        nanos -= delay - timeLeft; //更新超时时间
                    } finally {
    
    
						//1.这里leader可能为空因为在当前线程阻塞的时候,其他入队操作的线程可能将leader赋值为null,leader为null说明 当前线程是被其他入队操作线程唤醒的
                        if (leader == thisThread)
                            leader = null; 
                    }
                }
            }
        }
    } finally {
    
    
//队列中还有元素,并且不存在leader线程了
        if (leader == null && q.peek() != null)
            available.signal(); //唤醒其他阻塞的在出队上的线程
        lock.unlock(); //释放锁
    }
}


public E take() throws InterruptedException {
    
    
    final ReentrantLock lock = this.lock; //全局锁
    lock.lockInterruptibly(); //可中断加锁
    try {
    
    
        for (;;) {
    
    
            E first = q.peek(); //获取队首元素不移除
            if (first == null) //队列为null
                available.await(); //阻塞当前线程等待被唤醒
            else {
    
     //队列中存在元素的情况
                long delay = first.getDelay(NANOSECONDS); //获取延迟时间
                if (delay <= 0) //元素已过期
                    return q.poll(); //直接返回该元素
                first = null; // don't retain ref while waiting
                if (leader != null) //队首元素的剩余延迟时间大于0,有其他线程也在出队操作
                    available.await(); //直接阻塞当前线程
                else {
    
     //队首为未过期元素并且当前没有其他线程出队阻塞
                    Thread thisThread = Thread.currentThread();
                    leader = thisThread; //将当前线程设置为leader
                    try {
    
    
                        available.awaitNanos(delay); //阻塞队首延迟时间后被唤醒
                    } finally {
    
     
						//leader可能为null,因为其他线程的入队操作导致的
                        if (leader == thisThread)
                            leader = null;
                    }
                }
            }
        }
    } finally {
    
    
		//队列中还含有其他元素并且leader为null
        if (leader == null && q.peek() != null)
            available.signal(); //唤醒其他阻塞在出队操作上的线程
        lock.unlock(); //锁释放
    }
}

para resumir

  1. DelayQueue es una cola retrasada y los elementos de la cola deben implementar la interfaz retrasada.
  2. La capa inferior de la cola utiliza una cola ilimitada de prioridad de montón completamente binaria
  3. La cola DelayQueue implementa BlockingQueue, que puede quitar de la cola las operaciones de bloqueo de la cola (quitar de la cola e ingresar a la operación mientras se usa un bloqueo global)
    : tome, cuando la cola es nula, bloquee el hilo actual y espere a que se activen otros hilos. la cola no es nula, juzgue Si el elemento al principio de la cola ha expirado, se devolverá directamente después de la expiración. Si el líder es nulo, se determina si el hilo está bloqueado solo por tiempo o bloqueado esperando otro hilos para despertar. encuesta, devuelve directamente cuando hay un elemento caducado en la cola sin parámetros, de lo contrario devuelve nulo. Cuando se toman parámetros, es similar a tomar, excepto que se agrega un período de tiempo de espera (cuánto tiempo puede esperar el hilo), y se devolverá nulo directamente si se excede el período de tiempo de espera.
    Únase al equipo: oferta, colocación (oferta llamada directamente), devolución verdadera directamente cuando se une al equipo con éxito.
  4. La cola de bloqueo contiene un subproceso líder de variable miembro. Cuando se están tomando varios subprocesos, no es necesario que cada subproceso se despierte automáticamente después de esperar un tiempo específico. Solo el primer subproceso de toma realiza dicho procesamiento y todos los subprocesos de toma posteriores Es necesario para determinar si el líder está vacío para determinar si el hilo está en espera directamente. (El juicio de giro del método awaitNonas es ineficaz).
  5. DelayQueue tiene una variable de condición para manejar la activación y el bloqueo entre subprocesos. Para usar el método relacionado, primero se debe adquirir el bloqueo relevante, y el subproceso debe obtener primero el bloqueo relevante cuando se espera o awaitNonas o se liberan todos los recursos de bloqueo actuales, y competir por la adquisición de nuevo cuando se despierte de nuevo.

Interfaz retrasada

public interface Delayed extends Comparable<Delayed> {
    
    

    /**
     * Returns the remaining delay associated with this object, in the
     * given time unit.
     *
     * @param unit the time unit
     * @return the remaining delay; zero or negative values indicate
     * that the delay has already elapsed
     */
    long getDelay(TimeUnit unit);
}

Supongo que te gusta

Origin blog.csdn.net/weixin_41237676/article/details/109105221
Recomendado
Clasificación