ArrayBlockingQueue源码解析(JDK1.8)

    ArrayBlockingQueue是一个基于用数组实现的有界阻塞队列。此队列按照先进先出的原则对元素进行排序

一、成员变量

//存放元素的数组
final Object[] items;
//队头
int takeIndex;
//队尾
int putIndex;
//队列中的元素个数
int count;
//
final ReentrantLock lock;
//监视队列是否为空的监视器
private final Condition notEmpty;
//监视队列是否到达容量的监视器
private final Condition notFull;

二、构造方法

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();
}

    根据传入的fair的值来构造公平还是非公平的容量为capacity的阻塞队列

public ArrayBlockingQueue(int capacity) {
    this(capacity, false);
}

    只传入容量的构造方法构造为非公平的阻塞队列

三、操作方法

private void enqueue(E x) {
    final Object[] items = this.items;
    items[putIndex] = x;
    if (++putIndex == items.length)
        putIndex = 0;
    count++;
    notEmpty.signal();
}

    入队列的操作方法,很简单,将元素放到队尾索引,将队尾索引+1,如果入队后队列已满,则重置队尾,队列长度加1,唤醒等待因为无法取到元素二阻塞的线程。注意到,这个队列是一个循环队列

1、offer方法

public boolean offer(E e) {
    //入队元素判空
    checkNotNull(e);
    final ReentrantLock lock = this.lock;
    //获取锁
    lock.lock();
    try {
        //如果队列已满,返回false
        if (count == items.length)
            return false;
        else {
            //入队,返回true
            enqueue(e);
            return true;
        }
    } finally {
        //释放锁
        lock.unlock();
    }
}

   可以看到,offer方法会返回特殊值并且不阻塞。offer方法在队列已满时,返回false,并没有阻塞。入队成功返回true。

    2、put方法

public void put(E e) throws InterruptedException {
    //入队元素判空
    checkNotNull(e);
    final ReentrantLock lock = this.lock;
    //获取锁
    lock.lockInterruptibly();
    try {
        //如果队列已满,则阻塞该线程
        while (count == items.length)
            notFull.await();
        //队列未满,则入队
        enqueue(e);
    } finally {
        lock.unlock();
    }
}

    可以看到,如果队列已满,put方法会阻塞线程。

private E dequeue() {
    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;
}

    dequeue是出队的操作方法,很简单,取出队尾索引对应的值,将队尾索引对应的元素置空,如果出队索引到达队列长度,则重置出队索引,队列长度减1,唤醒因入队而阻塞的线程,最后返回对应的元素。

    3、poll方法

public E poll() {
    final ReentrantLock lock = this.lock;
    //获取锁
    lock.lock();
    try {
        //如果队列无元素返回null,不然调用dequeue
        return (count == 0) ? null : dequeue();
    } finally {
        lock.unlock();
    }
}

        可以看到,poll方法与offer方法类似,也是一个返回特殊值的方法,并且也不阻塞线程。如果队列为空返回null,不然出队头的元素

    4、take方法

public E take() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    //加锁
    lock.lockInterruptibly();
    try {
        //如果队列为空,则阻塞线程
        while (count == 0)
            notEmpty.await();
        //队列不为空返回队头元素
        return dequeue();
    } finally {
        lock.unlock();
    }
}

        可以看到,take方法和put方法类似,会阻塞线程。

还有等待多长时间的入队和出队方法,因为只是加入了定时器,其余和上述方法没区别,所以我就不说了。

阻塞队列提供了4类方法,如下图所示




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章