美文网首页
Android多线程编程 - 阻塞队列原理

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

作者: BlueSocks | 来源:发表于2023-07-27 20:05 被阅读0次

    以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;
       }
    
    

    相关文章

      网友评论

          本文标题:Android多线程编程 - 阻塞队列原理

          本文链接:https://www.haomeiwen.com/subject/gbqrpdtx.html