PriorityBlockingQueue 源码分析

  之前分析过ArrayBlockingQueue,它的特点是

  1 有限,不会扩容

  2 严格的先进先出

  今天要介绍的PriorityBlockingQueue,正好突破了这两点,第一它是无限的,第二它是根据元素的大小进行排序的的队列

  排序所使用的算法是堆排序,而且是小顶堆,也就是说值越小越优先

  补充一下,默认确实是小顶堆,但是构造方法提供了比较器,也可以实现大顶堆。

  

public PriorityQueue(Comparator<? super E> comparator) {
    this(DEFAULT_INITIAL_CAPACITY, comparator);
}

PriorityQueue<Integer> queue = new PriorityQueue<>((num1, num2) -> num2 - num1);

 

一 入队

public boolean offer(E e) {
        if (e == null)
            throw new NullPointerException();
        final ReentrantLock lock = this.lock;
        lock.lock();
        int n, cap;
        Object[] array;
        while ((n = size) >= (cap = (array = queue).length))
            tryGrow(array, cap);//扩容,扩容的条件是size已经到头了 这个和hashmap可不一样
        try {
            Comparator<? super E> cmp = comparator;
            if (cmp == null)
                siftUpComparable(n, e, array);//堆调整,n始终是当前的size
            else
                siftUpUsingComparator(n, e, array, cmp);
            size = n + 1;//有lock包裹着不用加volatile
            notEmpty.signal();//唤醒等待线程
        } finally {
            lock.unlock();
        }
        return true;
    }

 

private static <T> void siftUpComparable(int k, T x, Object[] array) {
        Comparable<? super T> key = (Comparable<? super T>) x;
        while (k > 0) {
            int parent = (k - 1) >>> 1;
            Object e = array[parent];
            if (key.compareTo((T) e) >= 0)
                break;
            array[k] = e;
            k = parent;
        }
        array[k] = key;
    }

入队就是从下到上,从右到左的找该元素应该所在的位置

二 出队列

public E poll() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return dequeue();
        } finally {
            lock.unlock();
        }
    }
private E dequeue() {
        int n = size - 1;
        if (n < 0)
            return null;
        else {
            Object[] array = queue;
            E result = (E) array[0];//每次出队都是第0个
            E x = (E) array[n];//把当前的最后那个取出来缓存起来
            array[n] = null;
            Comparator<? super E> cmp = comparator;
            if (cmp == null)
                siftDownComparable(0, x, array, n);//从0开始往下走,逐渐调整
            else
                siftDownUsingComparator(0, x, array, n, cmp);
            size = n;
            return result;
        }
    }

 

private static <T> void siftDownComparable(int k, T x, Object[] array,
                                               int n) {
        if (n > 0) {
            Comparable<? super T> key = (Comparable<? super T>)x;
            int half = n >>> 1;           // loop while a non-leaf
            while (k < half) {
                int child = (k << 1) + 1; // assume left child is least
                Object c = array[child];
                int right = child + 1;
                if (right < n &&
                    ((Comparable<? super T>) c).compareTo((T) array[right]) > 0)
                    c = array[child = right];
                if (key.compareTo((T) c) <= 0)
                    break;
                array[k] = c;
                k = child;
            }
            array[k] = key;
        }
    }

 出队列就是把堆头取出来,然后进行堆调整。

posted on 2020-11-30 18:20  MaXianZhe  阅读(99)  评论(0编辑  收藏  举报

导航