Android多线程编程 - 阻塞队列原理

2023-07-27  本文已影响0人  BlueSocks

以ArrayBlockingQueue为例,我们先来看看代码:

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

    private static final long serialVersionUID = -817911632652898426L;
    /** The queued items */
    final Object[] items;
    /** items index for next take, poll, peek or remove */
    int takeIndex;
    /** items index for next put, offer, or add */
    int putIndex;
    /** Number of elements in the queue */
    int count;
    final ReentrantLock lock;
    /** Condition for waiting takes */
    private final Condition notEmpty;
    /** Condition for waiting puts */
    private final Condition notFull;
 ...省略
 }

从上面代码可以看出ArrayBlockingQueue是维护一个Object类型的数组,takeIndex和putIndex分别表示队首元素和队尾元素的下标,count表示队列中元素的个数,lock则是一个可重入锁,notEmpty和notFull是等待条件。接下来我们看看关键方法put: Java

public void put(E e) throws InterruptedException {
    if (e == null) throw new NullPointerException();
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        while (count == items.length)
            notFull.await();
        enqueue(e);
    } finally {
        lock.unlock();
    }
}

从put方法的实现可以看出,它先获取了锁,并且获取的是可中断锁,然后判断当前元素个数是否等于数组的长度,如果相等,则调用notFull.await()进行等待,当被其他线程唤醒时,通过enqueue(e)方法插入元素,最后解锁。

/**
  * Inserts element at current put position, advances, and signals.
  * Call only when holding lock.
  */
 private void enqueue(E x) {
     // assert lock.getHoldCount() == 1;
     // assert items[putIndex] == null;
     final Object[] items = this.items;
     items[putIndex] = x;
     if (++putIndex == items.length) putIndex = 0;
     count++;
     notEmpty.signal();
 }

插入成功后,通过notEmpty唤醒正在等待取元素的线程。再来看看take方法:

public E take() throws InterruptedException {
     final ReentrantLock lock = this.lock;
     lock.lockInterruptibly();
     try {
         while (count == 0)
             notEmpty.await();
         return dequeue();
     } finally {
         lock.unlock();
     }
 }

跟put方法实现类似,put方法等待的是notFull信号,而take方法等待的是notEmpty信号。在take方法中,如果可以取元素,则通过dequeue方法取得元素,下面是dequeue方法的实现:

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;
       if (++takeIndex == items.length) takeIndex = 0;
       count--;
       if (itrs != null)
           itrs.elementDequeued();
       notFull.signal();
       return x;
   }

上一篇下一篇

猜你喜欢

热点阅读