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類方法,如下圖所示




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