代码改变世界

Java并发编程--阻塞队列

2017-08-25 14:46  deadMan_wyy  阅读(148)  评论(0编辑  收藏  举报

本文主要java.util.concurrent包下提供主要的几种阻塞队列以及其主要方法的介绍(内容基于JDK1.7)

一.几种主要的阻塞队列

1. ArrayBlockQueue:基于数组的有界阻塞队列。队列按 FIFO(先进先出)原则对元素进行排序。此类支持对等待的生产者线程和消费者线程进行排序的可选公平策略。默认情况下,不保证是这种排序。

2. LinkedBlockQueue:基于链表实现的有界阻塞队列。队列中元素FIFO(先进先出),创建对象如果没有明确大小,默认值是Integer.MAX_VALUE。

3. PriorityBlockingQueue:基于PriorityQueue实现的无界阻塞队列,队列不允许null元素,也不允许插入不可比较的对象

二.阻塞队列中的几个主要方法

阻塞队列包括了非阻塞队列中的大部分方法,除此之外,阻塞队列提供了另外4个非常有用的方法:

  put(E e)

  take()

  offer(E e,long timeout, TimeUnit unit)

  poll(long timeout, TimeUnit unit)

  

  put方法用来向队尾存入元素,如果队列满,则等待;

  take方法用来从队首取元素,如果队列为空,则等待;

  offer方法用来向队尾存入元素,如果队列满,则等待一定的时间,当时间期限达到时,如果还没有插入成功,则返回false;否则返回true;

  poll方法用来从队首取元素,如果队列空,则等待一定的时间,当时间期限达到时,如果取到,则返回null;否则返回取得的元素;

三.阻塞队列的实现原理

我们以ArrayBlockQueue为例,探讨下其基本思想

ArrayBlockQueue类中主要成员变量:

/** The queued items */
    final Object[] items;

    //队列首部元素下标
    int takeIndex;

    //队列尾部下标
    int putIndex;

    //队列元素个数
    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;

 下面我们主要看下ArrayBlockQueue类的put和take方法

    /**
     * Inserts the specified element at the tail of this queue, waiting
     * for space to become available if the queue is full.
     *
     * @throws InterruptedException {@inheritDoc}
     * @throws NullPointerException {@inheritDoc}
     */
    public void put(E e) throws InterruptedException {
        //检查元素是否为null
        checkNotNull(e);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            //队列已满,put线程等待
            while (count == items.length)
                notFull.await();
            
            //队列不满,进行入队列操作
            insert(e);
        } finally {
            lock.unlock();
        }
    }

    /**
     * Inserts element at current put position, advances, and signals.
     * Call only when holding lock.
     */
    private void insert(E x) {
        items[putIndex] = x;
        putIndex = inc(putIndex);
        ++count;
        
        //唤醒一个等待线程
        notEmpty.signal();
    }

take方法与put方法类似

     public E take() throws InterruptedException {
            final ReentrantLock lock = this.lock;
            lock.lockInterruptibly();
            try {
                while (count == 0)
                    notEmpty.await();
                return extract();
            } finally {
                lock.unlock();
            }
        }
     
       /**
         * Extracts element at current take position, advances, and signals.
         * Call only when holding lock.
         */
        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;
        }

部分内容来源网络,仅供参考