• ArrayBlockingQueue源码分析


    ArrayBlockingQueue是一个基于数组实现的有界的阻塞队列。

    属性

        //底层存储元素的数组。为final说明一旦初始化,容量不可变,所以是有界的。
        final Object[] items;
    
        //下一个take, poll, peek or remove操作的index位置
        int takeIndex;
        
        //下一个put, offer, or add操作的index位置
        int putIndex;
    
        // 元素数量
        int count;
    
        /**
         * 用于并发控制:使用经典的双Condition算法
         */
        final ReentrantLock lock;
        /** 获取操作等待条件 */
        private final Condition notEmpty;
        /** 插入操作等待条件 */
        private final Condition notFull;

    添加操作

    1.add操作(不常用)

    add()是最原始的方法。当队列满时,会抛出IllegalStateException。

        public boolean add(E e) {
            return super.add(e);
        }
        
        // 父类AbstractQueue中的add()
        public boolean add(E e) {
            if (offer(e))
                return true;
            else
                throw new IllegalStateException("Queue full");
        }

    2.offer操作

    offer有两个版本。
    不带超时版本:队列满时,直接返回false。
    带超时版本:队列满时,阻塞直到队列可用。

        public boolean offer(E e) {
            checkNotNull(e);
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                //队列已满,直接返回false
                if (count == items.length)
                    return false;
                else {//未满,则插入元素
                    insert(e);
                    return true;
                }
            } finally {
                lock.unlock();
            }
        }
        
        /**offer,带超时版本**/
        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 {
                //不停判断是否满了
                while (count == items.length) {
                    //超时,则直接返回false
                    if (nanos <= 0)
                        return false;
                    //队列已满,则等待
                    nanos = notFull.awaitNanos(nanos);
                }
                //阻塞直到队列可用,则插入元素
                insert(e);
                return true;
            } finally {
                lock.unlock();
            }
        }

    3.put操作

        public void put(E e) throws InterruptedException {
            //检查参数是否为null。为null则抛异常
            checkNotNull(e);
            final ReentrantLock lock = this.lock;
            //加锁。可中断
            lock.lockInterruptibly();
            try {
                //队列已满则一直等待,直到队列有可用空间
                while (count == items.length)
                    notFull.await();//等待
                //队列空闲时,插入元素
                insert(e);
            } finally {
                //释放锁
                lock.unlock();
            }
        }

    删除操作

    1.poll操作

        public E poll() {
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                return (count == 0) ? null : extract();
            } finally {
                lock.unlock();
            }
        }
        
        private E extract() {
            final Object[] items = this.items;
            E x = this.<E>cast(items[takeIndex]);//强转
            //删除
            items[takeIndex] = null;
            takeIndex = inc(takeIndex);
            --count;
            //通知
            notFull.signal();
            return x;
        }
        
        /**poll,带超时版本**/
        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 extract();
            } finally {
                lock.unlock();
            }
        }

    2.take操作

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

    3.peek操作

        public E peek() {
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                return (count == 0) ? null : itemAt(takeIndex);
            } finally {
                lock.unlock();
            }
        }

    清空操作

        public void clear() {
            final Object[] items = this.items;
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                //依次将所有元素设为null
                for (int i = takeIndex, k = count; k > 0; i = inc(i), k--)
                    items[i] = null;
                //count,putIndex,takeIndex都为0
                count = 0;
                putIndex = 0;
                takeIndex = 0;
    
                notFull.signalAll();
            } finally {
                lock.unlock();
            }
        }

    总结

    BlockingQueue接口提供了3个添加元素方法。

    • add:添加元素到队列里,添加成功返回true,如果队列已满则抛出IllegalStateException异常。不常用。
    • offer:添加元素到队列里,添加成功返回true,如果队列已满添加失败,返回false
    • put:添加元素到队列里,添加成功返回true,如果队列已满则阻塞直到队列可用

    同时,BlockingQueue接口提供了3个获取(并删除)元素的方法。

    • remove:
    • poll:返回队列头部元素。队列为空时,返回null
    • take:队列为空时,会阻塞直到有数据加入到队列中
  • 相关阅读:
    SpringBoot(一)_快速实战搭建项目
    maven入门 (二)_私服安装与上传下载
    maven入门(一)
    Ionic 2 开发(一)_安装与目录结构
    echarts添加点击事件
    win下 git gui 使用教程
    安装centos6.3
    PAT甲级题分类汇编——图
    PAT甲级题分类汇编——树
    PAT甲级题分类汇编——理论
  • 原文地址:https://www.cnblogs.com/rouqinglangzi/p/10291918.html
Copyright © 2020-2023  润新知