ArrayBlockingQueue 源碼閱讀與分析

 ArrayBlockingQueue 源碼閱讀與分析

       通過這個類的名字,可以知道ArrayBlockingQueue是一個底層使用數組實現,具有隊列特點的先進先出以及線程安全的一個集合類,他還可以實現指定時間的阻塞讀寫,也就是可以解決生產者消費者問題的阻塞隊列。

首先來看一下它的構造方法:

public ArrayBlockingQueue(int capacity) {

        this(capacity, false);

 

    }

public ArrayBlockingQueue(int capacity, boolean fair) {

        if (capacity <= 0)

            throw newIllegalArgumentException();

        this.items = newObject[capacity];

        lock = newReentrantLock(fair);

        notEmpty =lock.newCondition();

        notFull =  lock.newCondition();

    }

       這是前兩個構造方法,可以發現一個問題,就是它沒有默認構造器,傳入的參數即爲創建的對象數組的大小,同時初始化鎖和這個鎖上的兩個Condition,一個爲 notEmpty,用作隊列空時,進行take操作的等待;另一個爲notFull,作用是隊列滿時,put操作的等待。

 

   首先來看一下offer方法,offer方法有兩個重載的實現, 用於插入元素至數組的尾部。

    先看一下不帶參數的offer方法:

lock.lock();

        try {

            if (count ==items.length)

                return false;

            else {

                insert(e);

                return true;

            }

        } finally {

            lock.unlock();

        }

         其中的count是隊列中的元素的個數,items就是存值的數組,在數組滿的情況下則不進入等待,而是直接返回 false。不滿的情況下,會進入insert方法,會執行notEmpty.signal();,喚醒再隊列爲空時take操作等待的線程

       它還有一個有三個參數的重載方法,如數組已滿,則進入等待,直到以下三種情況時才繼續:被喚醒、到達指定的時間或當前線程被中斷(interrupt)。此方法首先將指定的時間轉換爲納秒,然後執行加鎖操作,如數組未滿,則將對象插入數組,如數組已滿,且已超過指定的時間,則返回 false;如未超過指定的時間,則調用 notFull condition 的 awaitNanos 方法進行等待,如爲被喚醒或超時,則繼續判斷數組是否已滿;如線程被 interrupt,則直接拋出 InterruptedException。

 

再來看一下put 方法

具體的代碼如下:

public void put(E e) throwsInterruptedException {

       checkNotNull(e);

       final ReentrantLock lock = this.lock;

       lock.lockInterruptibly();

       try {

           while (count == items.length)

                notFull.await();

           insert(e);

       } finally {

           lock.unlock();

       }

    }

    可以看到,這個方法在數組已滿的情況下會一直等待,直到數組不爲空或線程被 interrupt。

 

     接下來再來看一下poll方法,此方法用於獲取隊列中的第一個元素。和offer一樣,也有兩個重載。

public E poll() {

        final ReentrantLocklock = this.lock;

        lock.lock();

        try {

            return (count ==0) ? null : extract();

        } finally {

            lock.unlock();

        }

    }

       這是不帶時間參數的 poll 方法,它會在在數組中元素個數爲零的情況下則不進入等待,而是直接返回 null,不爲空的情況下執行extract()方法,執行notFull.signal();喚醒put阻塞的線程。

        還有一個是有三個參數的poll(E,long,TimeUnit)方法。如隊列中沒有元素,則進入等待,與 offer(E,long,TimeUnit)相同,它也是在三種情況後繼續。 首先將指定的時間轉化爲納秒,並進行加鎖,如數組中的元素個數不爲零,則從當前的對象數組中獲取最後一個元素,在獲取後將該位置上的元素設置爲 null;如數組中的元素個數爲零,首先判斷剩餘的等待時間是否小於零,如小於則返回 null,如大於則調用 notEmpty condition 的 awaitNanos 方法進行等待,如爲被喚醒或超時,則繼續判斷數組中元素個數是否不爲零;如線程被 interrupt,則直接拋出 interruptedException。

 

 

    最後再看一下take方法,源碼如下:

  publicE take() throws InterruptedException {

       final ReentrantLock lock = this.lock;

       lock.lockInterruptibly();

       try {

           while (count == 0)

                notEmpty.await();

           return extract();

       } finally {

           lock.unlock();

       }

    }

 

          可以看到,調用 take 方法,此方法在數組爲空的情況下會一直等待,直到數組不爲空或線程被 interrupt。再調用extract方法,取出隊首的元素。

 

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