3.12 ArrayBlockingQueue详解

3.12 ArrayBlockingQueue

       ArrayBlockingQueue是阻塞队列BolockingQueue接口基于数组的实现,该特点由名字也可看出。



3.12.1 ArrayBlockingQueue继承关系

       ArrayBlockingQueue继承了抽象类AbstractQueue并且实现了BlockingQueue接口。
3.12 ArrayBlockingQueue详解_第1张图片


3.12.2 ArrayBlockingQueue用法

       创建一个ArrayBlockingQueue,必须要指定该队列长度,注意该队列长度是固定的,所以分配适当的长度非常重要,视具体的需求而定。

BlockingQueue<Integer> queue = new ArrayBlockingQueue(1024);

       入队方法offer,还可以使用入队的其他方法

queue.offer(1);
queue.offer(3);

       出队poll,还有其他方法入take

Integer poll = queue.poll();
try {
     
    Integer take = queue.take();
} catch (InterruptedException e) {
     
    e.printStackTrace();
}

3.12.3 ArrayBlockingQueue内部组成(源码解析)

/** 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;

       ArrayBlockingQueue中存放元素的数组为一个Object[] items的数组,另外有一个ReentrantLock lock用于并发控制,Codition notEmpty是一个ConiditonObject类对象,内部维护了一个CLH链表,该聊表维护的是一个等待线程之间的关系,其源码可在AbstractQueuedSynchronizer抽象类中找到。



3.12.4 ArrayBlockingQueue构造方法

public ArrayBlockingQueue(int capacity) {
     
    this(capacity, false);
}
//初始化容器数组和锁和CLH队列
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();
}
//和上边类似,只是讲集合添加到队列中,主要添加过程中使用了锁
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;
        putIndex = (i == capacity) ? 0 : i;
    } finally {
     
        lock.unlock();
    }
}



3.12.5 ArrayBlockingQueue入队和出队

       offer方法,和一般队列并没有区别,只是加了锁,锁的释放一定在finally代码块中,保证锁的释放。

public boolean offer(E e) {
     
    checkNotNull(e);
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
     
        if (count == items.length)
            return false;
        else {
     
            enqueue(e);
            return true;
        }
    } finally {
     
        lock.unlock();
    }
}

       出队方法offer和take,注意二者的区别,take方法当队列为空的时候线程会等待,而poll方法在队列为空的时候直接返回null,对于阻塞队列如该队列长时间为空的情况下使用take方法是很浪费资源的。

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

public E take() throws InterruptedException {
     
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
     
        while (count == 0)
        	//注意这一行代码
            notEmpty.await();
        return dequeue();
    } finally {
     
        lock.unlock();
    }
}

       总结ArrayBlockingQueue是阻塞队列基于数组的实现,需要注意的是内部使用的锁是ReentrantLock,并且了解不同出队方法的区别。

你可能感兴趣的:(#,3,多线程和并发,java,并发编程,BlockingQueue解析,阻塞队列源码解析,基于数组的阻塞队列详解)