阻塞队列之PriorityBlockingQueue

来源:互联网 发布:java write 编辑:程序博客网 时间:2024/06/07 01:53

public class PriorityBlockingQueue<E> extends AbstractQueue<E>    implements BlockingQueue<E>, java.io.Serializable 
PriorityBlockingQueue是一个无界的阻塞队列,排序规则和PriorityQueue一样,但只是逻辑上无界,因为尝试添加可能会因资源耗尽(OutOfMermoryError)而失败。

该类不能添加null元素,会抛出NullPointerException;不能插入没有实现Comparable(不可比较的对象),会抛出ClassCastException

该类使用数组实现的二叉堆实现了优先级队列,同时增加了ReentrantLock锁实现阻塞达到线程安全。

1,初始容量为11,,扩容方法:

private void tryGrow(Object[] array, int oldCap) {    lock.unlock(); // must release and then re-acquire main lock    Object[] newArray = null;    if (allocationSpinLock == 0 &&        UNSAFE.compareAndSwapInt(this, allocationSpinLockOffset,                                 0, 1)) {        try {            int newCap = oldCap + ((oldCap < 64) ?                                   (oldCap + 2) : // grow faster if small                                   (oldCap >> 1));            if (newCap - MAX_ARRAY_SIZE > 0) {    // possible overflow                int minCap = oldCap + 1;                if (minCap < 0 || minCap > MAX_ARRAY_SIZE)                    throw new OutOfMemoryError();                newCap = MAX_ARRAY_SIZE;            }            if (newCap > oldCap && queue == array)                newArray = new Object[newCap];        } finally {            allocationSpinLock = 0;        }    }    if (newArray == null) // back off if another thread is allocating        Thread.yield();    lock.lock();    if (newArray != null && queue == array) {        queue = newArray;        System.arraycopy(array, 0, newArray, 0, oldCap);    }}
当旧容量小于64时,新容量=旧容量*2+2;大于64时,新容量 = 1.5*旧容量。之后还要看师傅超出最大容量。

2,入队offer()的逻辑和PriorityQueue一样,只是加了锁来实现线程安全。

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);    try {        Comparator<? super E> cmp = comparator;        if (cmp == null)            siftUpComparable(n, e, array);        else            siftUpUsingComparator(n, e, array, cmp);        size = n + 1;        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;}


3,出队poll(),take()

public E poll() {    final ReentrantLock lock = this.lock;    lock.lock();    try {        return dequeue();    } finally {        lock.unlock();    }}public E take() throws InterruptedException {    final ReentrantLock lock = this.lock;    lock.lockInterruptibly();    E result;    try {        while ( (result = dequeue()) == null)            notEmpty.await();    } finally {        lock.unlock();    }    return result;}
private E dequeue() {    int n = size - 1;    if (n < 0)        return null;    else {        Object[] array = queue;        E 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;    }}
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;    }}