Cola de bloqueo y cola de no bloqueo en JAVA

Cola de bloqueo

Cada clase de implementación en la interfaz BlockingQueue y parte de la introducción del código fuente, BlockingQueue proporciona cuatro métodos diferentes para insertar, eliminar y obtener operaciones de elementos para su uso en diferentes escenarios:

  • Lanza una excepción, si la cola está vacía o la cola está llena, lanza una excepción directamente
  • Devuelve un valor especial (nulo o verdadero / falso)
  • Bloquear esperando esta operación hasta que esta operación sea exitosa
  • Bloquear la espera de esta operación hasta que se realice correctamente o hasta que expire el tiempo especificado.
operando Lanzar excepción Volver vacío Espera de bloqueo se acabó el tiempo
insertar añadir (e) oferta (e) poner (e) oferta (e, tiempo, unidad)
Eliminar retirar() encuesta() llevar() encuesta (tiempo, unidad)
No elimine el encabezado de devolución elemento() ojeada() - -
BlockingQueue,我们的关注点应该在 put(e) 和 take() 这两个方法,因为这两个方法是带阻塞的

ArrayBlockingQueue

ArrayBlockingQueue es una clase de implementación de cola limitada de la interfaz BlockingQueue, y la capa inferior se implementa mediante una matriz.

poner

blockingQueue.put(ball);

public void put(E e) throws InterruptedException {
    
    
   checkNotNull(e);
   //获取独占锁
   final ReentrantLock lock = this.lock;
   //上锁
   lock.lockInterruptibly();
   try {
    
    
       //如果队列中的元素等于队列长度
       while (count == items.length)
           //非满阻塞,队列为空阻塞
           notFull.await();
       //如果队列中还可以存放数据,加入到队列
       enqueue(e);
   } finally {
    
    
       lock.unlock();
   }
}
private void enqueue(E x) {
    
    
    //底层使用数组实现的,数组下标赋值
    final Object[] items = this.items;
    items[putIndex] = x;
    if (++putIndex == items.length)
        putIndex = 0;
    count++;
    //唤醒非空等待,就是唤醒取值等待
    notEmpty.signal();
}

blockQueue.take ()

public E take() throws InterruptedException {
    
    
    //获取锁
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
    
    
       //非空阻塞
        while (count == 0)
            notEmpty.await();
        //取队列数据
        return dequeue();
    } finally {
    
    
        lock.unlock();
    }
}
private E dequeue() {
    
    
     //取数组下标数据 老下标 置空
    final Object[] items = this.items;
    @SuppressWarnings("unchecked")
    E x = (E) items[takeIndex];
    items[takeIndex] = null;
    if (++takeIndex == items.length)
        takeIndex = 0;
    count--;
    if (itrs != null)
        itrs.elementDequeued();
    //唤醒put中的阻塞线程
    notFull.signal();
    return x;
}

El código fuente es muy simple, no hablemos del extra

LinkedBlockingQueue

A diferencia de ArrayBlockingQueue, aquí se utilizan dos bloqueos y dos condiciones

public void put(E e) throws InterruptedException {
    
    
     if (e == null) throw new NullPointerException();
     //用于唤醒读线程取值
     int c = -1;
     Node<E> node = new Node<E>(e);
     //获取put锁
     final ReentrantLock putLock = this.putLock;
     final AtomicInteger count = this.count;
     //上锁
     putLock.lockInterruptibly();
     try {
    
    
         //队列是否满了 满了阻塞notFull
         while (count.get() == capacity) {
    
    
             notFull.await();
         }
         //加入队列
         enqueue(node);
         c = count.getAndIncrement();
         //队列没有满 唤醒  另一个put线程
         if (c + 1 < capacity)
             notFull.signal();
     } finally {
    
    
         putLock.unlock();
     }
     //如果 c == 0,那么代表队列在这个元素入队前是空的
     if (c == 0)
         //那么所有的读线程都在等待 notEmpty 这个条件,等待唤醒,这里做一次唤醒操作
         signalNotEmpty();
 }

poner en cola

private void enqueue(Node<E> node) {
    
    
    last = last.next = node;
}
private void signalNotEmpty() {
    
    
    final ReentrantLock takeLock = this.takeLock;
    takeLock.lock();
    try {
    
    
        notEmpty.signal();
    } finally {
    
    
        takeLock.unlock();
    }
}

llevar

public E take() throws InterruptedException {
    
    
     E x;
     int c = -1;
     final AtomicInteger count = this.count;
     //take锁
     final ReentrantLock takeLock = this.takeLock;
     takeLock.lockInterruptibly();
     try {
    
    
         //如果队列等于0 阻塞住
         while (count.get() == 0) {
    
    
             notEmpty.await();
         }
         //取队列数据
         x = dequeue();
         //取前队列中的长度
         c = count.getAndDecrement();
         if (c > 1)
             //如果队列中有数据唤醒其余线程取数据
             notEmpty.signal();
     } finally {
    
    
         takeLock.unlock();
     }
      // 如果 c == capacity,那么说明在这个 take 方法发生的时候,队列是满的
    // 既然出队了一个,那么意味着队列不满了,唤醒写线程去写
     if (c == capacity)
         signalNotFull();
     return x;
 }

DelayQueue

Cola de programación basada en el tiempo respaldada por el montón de prioridad

PriorityBlockingQueue

Cola de prioridad ilimitada compatible con el montón de prioridad

ConcurrentLinkedQueue

La capa inferior usa cas + loop, cas no puede agregar un loop, cola ilimitada.
Finalmente inserte los datos al final de la cola.

El valor también es una operación cas, por lo que no entraré en detalles aquí. En la víspera de Año Nuevo, prepárate para ir a la cama y comer.

public boolean offer(E e) {
    
    
   checkNotNull(e);
   final Node<E> newNode = new Node<E>(e);

   for (Node<E> t = tail, p = t;;) {
    
    
       Node<E> q = p.next;
       if (q == null) {
    
    
           if (p.casNext(null, newNode)) {
    
    
               if (p != t) // hop two nodes at a time
                   casTail(t, newNode);  // Failure is OK.
               return true;
           }
       }
       else if (p == q)
           p = (t != (t = tail)) ? t : head;
       else
           p = (p != t && t != (t = tail)) ? t : q;
   }
}

Supongo que te gusta

Origin blog.csdn.net/qq_37904966/article/details/113772686
Recomendado
Clasificación