¿Ha entendido ArrayBlockingQueue?

Visión de conjunto

Desde java5, jdk ha agregado el paquete concurrente, BlockingQueue en concurrente, que es la cola de bloqueo, BlockingQueue es solo una interfaz, y jdk proporciona clases de implementación enriquecidas para diferentes escenarios Este artículo trata sobre ArrayBlockingQueue.

ArrayBlockingQueue 简介

ArrayBlockingQueue hereda la clase AbstractQueue e implementa la interfaz BlockingQueue. Es una cola delimitada basada en arreglos. El bloqueo se implementa en función de ReentrantLock. Solo hay un objeto de bloqueo, lo que conduce a un bloqueo compartido para poner en cola / sacar de cola y no puede lograr acceso paralelo.

solicitud

1. En aplicaciones prácticas, la cantidad de datos debe considerarse completamente al configurar el tamaño de la matriz. Si el valor establecido es demasiado pequeño, fácilmente causará un bloqueo y el tamaño no se puede modificar durante la operación.
2. No se admite el elemento nulo; de lo contrario, se informará NullPointerException.

Método principal

Inserte la descripción de la imagen aquí
1. Insertar datos
(1) oferta (E e): Si la cola no está llena, devuelve verdadero, si la cola está llena, devuelve falso (no bloqueado).
(2) oferta (E e, tiempo de espera prolongado, unidad TimeUnit): puede establecer el tiempo de espera, si la cola está llena, espere. Si se excede el tiempo de espera, se devuelve falso.
(3) poner (E e): Sin valor de retorno, espere hasta que la cola desocupe un lugar.

2. Obtener datos
(1) poll (): Si hay datos, abandona el equipo, si no hay datos, devuelve nulo.
(2) encuesta (tiempo de espera largo, unidad TimeUnit): el tiempo de espera se puede configurar, si no hay datos, espere, si se excede el tiempo de espera, se devolverá un valor nulo.
(3) take (): Si hay datos, abandone el equipo. Si no hay datos, sigue esperando (bloqueando).

Análisis de código fuente

1.AbstractQueue

public class ArrayBlockingQueue<E> extends AbstractQueue<E>
        implements BlockingQueue<E>, java.io.Serializable

Herede la clase abstracta AbstractQueue e implemente la interfaz BlockingQueue.

2. Variables miembro

final Object[] items;//队列

    /** 下次出队下标(take、poll、remove) */
    int takeIndex;

    /** 下次入队下标(pull、offer、add) */
    int putIndex;

    /** 队列中元素个数 */
    int count;


    /** 锁 */
    final ReentrantLock lock;

    /** 等待条件(出队) */
    private final Condition notEmpty;

    /** 等待条件(入队) */
    private final Condition notFull;

    /**
     * 迭代器
     */
    transient Itrs itrs = null;

Como se puede ver en el código fuente, ArrayBlockingQueue es una cola basada en matrices y el bloqueo se basa en ReentrantLock.

3. Constructor

	public ArrayBlockingQueue(int capacity) {
    
    
        this(capacity, false);
    }
 
    public ArrayBlockingQueue(int capacity, boolean fair) {
    
    
        if (capacity <= 0)
            throw new IllegalArgumentException();
        this.items = new Object[capacity];
        lock = new ReentrantLock(fair);
        notEmpty = lock.newCondition();
        notFull =  lock.newCondition();
    }

Desde el código fuente, la longitud de la matriz debe establecerse para instanciar ArrayBlockingQueue, por lo que ArrayBlockingQueue es una cola acotada

4.oferta

	public boolean offer(E e) {
    
    
        //判断你是否为null,为null抛NullPointerException
        checkNotNull(e);
        //获取锁
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
    
    
            //如果队列已满,返回false
            if (count == items.length)
                return false;
            else {
    
    
                //入队,返回true
                enqueue(e);
                return true;
            }
        } finally {
    
    
            //释放锁
            lock.unlock();
        }
    }
    
    public boolean offer(E e, long timeout, TimeUnit unit)
            throws InterruptedException {
    
    
        //判断是否为null,为null抛NullPointerException
        checkNotNull(e);

        long nanos = unit.toNanos(timeout);
        //获取锁
        final ReentrantLock lock = this.lock;
        //lockInterruptibly优先考虑响应中断
        lock.lockInterruptibly();
        try {
    
    
            //如果队列已满
            while (count == items.length) {
    
    
                //超时直接返回false
                if (nanos <= 0)
                    return false;
                //生产线程堵塞nanos时间,也有可能被唤醒,如果超过nanos时间还未被唤醒,则nanos=0,再次循环,就会返回false
                nanos = notFull.awaitNanos(nanos);
            }
            //设置元素
            enqueue(e);
            return true;
        } finally {
    
    
            //释放锁
            lock.unlock();
        }
    }
    
    private void enqueue(E x) {
    
    
        // assert lock.getHoldCount() == 1;
        // assert items[putIndex] == null;
        //获取数组
        final Object[] items = this.items;
        //向入队下标数组设置元素
        items[putIndex] = x;
        //如果入队下标已经是最后一个,则证明队列已满,入队下标设置为0
        if (++putIndex == items.length)
            putIndex = 0;
        count++;
        //唤醒堵塞的消费线程
        notEmpty.signal();
    }

Se puede ver en el código fuente que la razón por la que el método de oferta se establece en nulo arrojará un error, porque el primer código es el método checkNotNull. Si la cola está llena, devuelve falso, y si la cola no está llena, devuelve verdadero.
La diferencia entre los dos métodos de oferta es si hay un tiempo de espera y la implementación es básicamente la misma.

5.put

	public void put(E e) throws InterruptedException {
    
    
        //判断是否为null,为null抛NullPointerException
        checkNotNull(e);
        //获取锁
        final ReentrantLock lock = this.lock;
        //lockInterruptibly优先考虑响应中断
        lock.lockInterruptibly();
        try {
    
    
            //如果队列已满
            while (count == items.length)
                //一直堵塞,直至被唤醒
                notFull.await();
            //设置元素
            enqueue(e);
        } finally {
    
    
            //释放锁
            lock.unlock();
        }
    }

Se puede ver en el código fuente que la diferencia entre los métodos put y offer es básicamente la misma, pero el método put se bloquea hasta que se despierta a través de notFull.await ()

6.poll

	public E poll() {
    
    
        //获取锁
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
    
    
            //如果队列为空,返回null,否则返回dequeue方法获取的值
            return (count == 0) ? null : dequeue();
        } 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 {
    
    
            //如果队列为空
            while (count == 0) {
    
    
                //当超时后,直接返回null
                if (nanos <= 0)
                    return null;
                //将线程堵塞nanos时间,堵塞时间内可能被唤醒,超过nanos时间,nanos=0,下次循环返回null
                nanos = notEmpty.awaitNanos(nanos);
            }
            //获取元素
            return dequeue();
        } finally {
    
    
            //释放锁
            lock.unlock();
        }
    }

    private E dequeue() {
    
    
        // assert lock.getHoldCount() == 1;
        // assert items[takeIndex] != null;
        final Object[] items = this.items;

        //通过出队下标获取元素
        @SuppressWarnings("unchecked")
        E x = (E) items[takeIndex];
        items[takeIndex] = null;
        //如果出队是数组中最后一个,下一个出队从0开始
        if (++takeIndex == items.length)
            takeIndex = 0;
        count--;
        if (itrs != null)
            itrs.elementDequeued();
        //唤醒生产的线程
        notFull.signal();
        return x;
    }

Como se puede ver en el código fuente, por qué el método de encuesta devuelve nulo si no obtiene los datos La diferencia entre las dos encuestas es si hay un tiempo de bloqueo y los otros son básicamente los mismos.

7.tomar

public E take() throws InterruptedException {
    
    
        //获取锁
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
    
    
            //如果队列为空,则堵塞,直至被唤醒
            while (count == 0)
                notEmpty.await();
            //获取元素
            return dequeue();
        } finally {
    
    
            //释放锁
            lock.unlock();
        }
    }

Se puede ver en el código fuente que tomar es muy simple, la lógica central es que la cola está vacía y espera hasta que se despierte.

Supongo que te gusta

Origin blog.csdn.net/qq_38306425/article/details/109352954
Recomendado
Clasificación