• ArrayBlockingQueue


    ArrayBlockingQueue

    BlockingQueue定义的常用方法有:

    放入数据:

    • offer(anObject):表示如果可能的话,将anObject加到BlockingQueue里,即如果BlockingQueue可以容纳,
          则返回true,否则返回false.(本方法不阻塞当前执行方法的线程)

    • offer(E o, long timeout, TimeUnit unit),可以设定等待的时间,如果在指定的时间内,还不能往队列中
          加入BlockingQueue,则返回失败。

    • put(anObject):把anObject加到BlockingQueue里,如果BlockQueue没有空间,则调用此方法的线程被阻断
          直到BlockingQueue里面有空间再继续.

    • add(anObject):把anObject加到BlockingQueue里,如果BlockQueue没有空间,则抛出一个IIIegaISlabEepeplian异常

    获取数据:

    • poll(time):取走BlockingQueue里排在首位的对象,若不能立即取出,则可以等time参数规定的时间,
          取不到时返回null;
    • poll(long timeout, TimeUnit unit):从BlockingQueue取出一个队首的对象,如果在指定时间内,
          队列一旦有数据可取,则立即返回队列中的数据。否则知道时间超时还没有数据可取,返回失败。
    • take():取走BlockingQueue里排在首位的对象,若BlockingQueue为空,阻断进入等待状态直到
          BlockingQueue有新的数据被加入;
    • remove(): 从BlockingQueue取出一个队首的对象,如果队列为空,则抛出一个NoSuchElementException异常
    • peek(): 返回队列头部的元素.如果队列为空,则返回null
    • drainTo():一次性从BlockingQueue获取所有可用的数据对象(还可以指定获取数据的个数),
          通过该方法,可以提升获取数据效率;不需要多次分批加锁或释放锁。

    ArrayBlockingQueue

    ArrayBlockingQueue使用一个指定长度的数组来存放对应的数据,这个长度在初始化的时候被指定,并且不能够再改变。如果往一个满的队列里面插入就会阻塞,如果从一个空的队列里面取内容也会阻塞。

    类定义:

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

    从上面可以看出ArrayBlockingQueue继承了AbstractQueue ,它使用了父类的add方法。

    变量:

       /** 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;
    
        /*
         * Concurrency control uses the classic two-condition algorithm
         * found in any textbook.
         */
    
        /** Main lock guarding all access */
        final ReentrantLock lock;
    
        /** Condition for waiting takes */
        private final Condition notEmpty;
    
        /** Condition for waiting puts */
        private final Condition notFull;
    
        /**
         * Shared state for currently active iterators, or null if there
         * are known not to be any.  Allows queue operations to update
         * iterator state.
         */
        transient Itrs itrs = null;
    

    解释都比较清楚,Itrs 实现比较复杂,以后仔细看下。

    构造函数:

      /**
         * Creates an {@code ArrayBlockingQueue} with the given (fixed)
         * capacity and default access policy.
         *
         * @param capacity the capacity of this queue
         * @throws IllegalArgumentException if {@code capacity < 1}
         */
        public ArrayBlockingQueue(int capacity) {
            this(capacity, false);
        }
    
        /**
         * Creates an {@code ArrayBlockingQueue} with the given (fixed)
         * capacity and the specified access policy.
         *
         * @param capacity the capacity of this queue
         * @param fair if {@code true} then queue accesses for threads blocked
         *        on insertion or removal, are processed in FIFO order;
         *        if {@code false} the access order is unspecified.
         * @throws IllegalArgumentException if {@code capacity < 1}
         */
        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();
        }
    
        /**
         * Creates an {@code ArrayBlockingQueue} with the given (fixed)
         * capacity, the specified access policy and initially containing the
         * elements of the given collection,
         * added in traversal order of the collection's iterator.
         *
         * @param capacity the capacity of this queue
         * @param fair if {@code true} then queue accesses for threads blocked
         *        on insertion or removal, are processed in FIFO order;
         *        if {@code false} the access order is unspecified.
         * @param c the collection of elements to initially contain
         * @throws IllegalArgumentException if {@code capacity} is less than
         *         {@code c.size()}, or less than 1.
         * @throws NullPointerException if the specified collection or any
         *         of its elements are null
         */
        public ArrayBlockingQueue(int capacity, boolean fair,
                                  Collection<? extends E> c) {
            this(capacity, fair);
    
            final ReentrantLock lock = this.lock;
            lock.lock(); // Lock only for visibility, not mutual exclusion
            try {
                int i = 0;
                try {
                    for (E e : c) {
                        checkNotNull(e);
                        items[i++] = e;
                    }
                } catch (ArrayIndexOutOfBoundsException ex) {
                    throw new IllegalArgumentException();
                }
                count = i;
                //如果集合的个数等于capacity,putIndex 就设置为0,否则设置为i
                putIndex = (i == capacity) ? 0 : i;
            } finally {
                lock.unlock();
            }
        }
    
    

    ArrayBlockingQueue 有三种构造函数,前两种都是定义一个空的queue,第三个是将一个集合转化为queue。

    add()

        public boolean add(E e) {
            return super.add(e);
        }
        
        public boolean add(E e) {
            if (offer(e))
                return true;
            else
                throw new IllegalStateException("Queue full");
        }
    

    add 函数 是使用了父类的add 方法,但实际上还是调用了offer,如果offer 失败了,就抛出了异常。

    offer()

        public boolean offer(E e) {
            checkNotNull(e);
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
            		//判断是否满了,如果满了,就返回false
                if (count == items.length)
                    return false;
                else {
                    enqueue(e);
                    return true;
                }
            } finally {
                lock.unlock();
            }
        }
    

    offer 里面主要调用了enqueue。

        private void enqueue(E x) {
            // assert lock.getHoldCount() == 1;
            // assert items[putIndex] == null;
            //赋值,并将putIndex 的下标+1
            final Object[] items = this.items;
            items[putIndex] = x;
            if (++putIndex == items.length)
                putIndex = 0;
            count++;
            //释放信号
            notEmpty.signal();
        }
    

    offer 还有另外的一种方式,就是设定等待的时间,这个等待的是用在notFull.awaitNanos()中

        public boolean offer(E e, long timeout, TimeUnit unit)
            throws InterruptedException {
    
            checkNotNull(e);
            long nanos = unit.toNanos(timeout);
            final ReentrantLock lock = this.lock;
            lock.lockInterruptibly();
            try {
            //这里增加了超时判断,如果超时了就返回false
                while (count == items.length) {
                    if (nanos <= 0)
                        return false;
                    nanos = notFull.awaitNanos(nanos);
                }
                enqueue(e);
                return true;
            } finally {
                lock.unlock();
            }
        }
    

    put()

        public void put(E e) throws InterruptedException {
            checkNotNull(e);
            final ReentrantLock lock = this.lock;
            lock.lockInterruptibly();
            //这里可以看出,如果队列满了,put一直在等待notFull condition,会造成阻塞
            try {
                while (count == items.length)
                    notFull.await();
                enqueue(e);
            } finally {
                lock.unlock();
            }
        }
    

    pull()

        public E poll() {
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
            //通过count判断队列是否为空,如果为空返回null,否则调用dequeue
                return (count == 0) ? null : 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;
            if (++takeIndex == items.length)
                takeIndex = 0;
            count--;
            if (itrs != null)
                itrs.elementDequeued();
            //dequeue会释放notFull.signal
            notFull.signal();
            return x;
        }
    

    poll也有等待指定时间的方式,具体和offer类似

        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) {
                    if (nanos <= 0)
                        return null;
                    nanos = notEmpty.awaitNanos(nanos);
                }
                return dequeue();
            } finally {
                lock.unlock();
            }
        }
    

    peek()

    peek就是返回数组中takeIndex指向的值

        public E peek() {
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                return itemAt(takeIndex); // null when queue is empty
            } finally {
                lock.unlock();
            }
        }
    

    remove(Object o)

    remove比较有意思,从takeIndex开始到putIndex,找到第一个与o相等的元素,并删除,然后更新itrs

        public boolean remove(Object o) {
            if (o == null) return false;
            final Object[] items = this.items;
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                if (count > 0) {
                    final int putIndex = this.putIndex;
                    int i = takeIndex;
                    do {
                        if (o.equals(items[i])) {
                            removeAt(i);
                            return true;
                        }
                        if (++i == items.length)
                            i = 0;
                    } while (i != putIndex);
                }
                return false;
            } finally {
                lock.unlock();
            }
        }
    

    take()

        public E take() throws InterruptedException {
            final ReentrantLock lock = this.lock;
            lock.lockInterruptibly();
            try {
            //阻塞
                while (count == 0)
                    notEmpty.await();
                return dequeue();
            } finally {
                lock.unlock();
            }
        }
    
  • 相关阅读:
    小程序与普通网页的区别
    小程序的结构
    Vuex四个map的方法使用
    Vuex的基本使用
    getters的使用
    nodeffi从入门到放弃(安装篇)
    nodejs如何调用c语言 (FFI)
    解决 nodegyp 错误问题
    NodeJS 调用C++(Nodeffi)
    Electron9.x +vue+ffinapi 调用Dll动态链接库
  • 原文地址:https://www.cnblogs.com/SpeakSoftlyLove/p/5618894.html
Copyright © 2020-2023  润新知