1. 程式人生 > >JDK原始碼分析之主要阻塞佇列實現類PriorityBlockingQueue

JDK原始碼分析之主要阻塞佇列實現類PriorityBlockingQueue

PriorityBlockingQueue類也是實現阻塞佇列的一種工具類,同Array BlockingQueue類和LinkedBlockingQueue一樣,最為訊息中介軟體的實現類。同步執行緒之間的訊息。

如果要分析PriorityBlockingQueue就必須要看看PriorityQueue是如何實現的了。類PriorityQueue和類PriorityBlockingQueue都是用Object [ ] queue來實現佇列中的元素的存

放,這一點和ArrayBlockingQueue類一樣。而且阻塞佇列類PriorityBlockingQueue的入列和出列操作都是使用一把同步鎖,但是LinkedBlockingQueue類的入列和出列操作都是自己使用獨立的一把鎖。

PriorityBlockingQueue類還有一個與前兩種阻塞佇列類不同的地方是:PriorityBlockingQueue對陣列queue存放的元素的排列順序進行了管理,陣列queue的第一個元素是最小的元素,因此每次取出來的元素都是最下的元素。queue陣列滿足在二叉樹結構下,所有的子二叉樹的根節點是在該樹下的最小值。

簡而言之,在二叉樹結構下,陣列元素在樹的根節點到葉子節點路徑中的所有節點的值都是有序排列的。

圖:

PriorityBlockingQueue類的屬性

    //存放佇列元素的陣列

    private transient Object[] queue;

    //佇列中元素的個數
    private transient int size;

    //維護陣列排序的時候進行比較的比較子
    private transient Comparator<? super E> comparator;
    //獲取佇列資源的同步鎖
    private final ReentrantLock lock;

    //鎖獲取條件
    private final Condition notEmpty;

PriorityBlockingQueue類使用的一些方法:

PriorityBlockingQueue類實際上就是比PriorityQueue類多了同步的功能。許多的入列演算法和出列演算法都是一樣的,下面就只給出PriorityQueue類的函式,而

PriorityBlockingQueue類似方法讀者自己進行分析,對比一下就會很簡單了,你自己也會同時掌握兩個類的使用。

PriorityQueue類出列操作

    //隊列出列是獲取並刪除在陣列的第一個元素位置,並將最後一個元素放在根節點位置,這個影響的只是二叉樹的一條路徑,然後對這條路徑進行半冒泡修復
    public E poll() {
        if (size == 0)
            return null;
        int s = --size;
        modCount++;
        E result = (E) queue[0];
        E x = (E) queue[s];
        queue[s] = null;
        if (s != 0)
            siftDown(0, x);
        return result;
    }

PriorityBlockingQueue類出列操作

/**
     * Mechanics for poll().  Call only while holding lock.
     */
    private E extract() {
        E result;
        int n = size - 1;
        if (n < 0)
            result = null;
        else {
            Object[] array = queue;
            result = (E) array[0];
            E x = (E) array[n];
            array[n] = null;
            Comparator<? super E> cmp = comparator;
            if (cmp == null)
                siftDownComparable(0, x, array, n);
            else
                siftDownUsingComparator(0, x, array, n, cmp);
            size = n;
        }
        return result;
    }
PriorityQueue類的入列操作
   public boolean offer(E e) {
        if (e == null)
            throw new NullPointerException();
        modCount++;
        int i = size;
        if (i >= queue.length)//如果佇列長度超容量,就增容
            grow(i + 1);
        size = i + 1;
        if (i == 0)//佇列為空時,直接插入佇列
            queue[0] = e;
        else	   //如果佇列中已經存在元素了,則插入元素後要維護佇列的排序(變異堆排序)
            siftUp(i, e);
        return true;
    }
PriorityQueue類的出列操作
    public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        E result;
        try {
            while ( (result = extract()) == null)
                notEmpty.await();
        } finally {
            lock.unlock();
        }
        return result;
    }
對於這些佇列的API就不做過多解釋了,如果讀者有興趣可以去了解更多

Priority BlockingQueue類和PriorityQueue類的演算法和資料結構以及思想都是一樣的,下一章我將把PriorityQueue類的所有原始碼的註釋分析發表出來,大家有興趣可以閱

讀下,註釋是我對PriorityQueue類的理解。