Java源码阅读之PriorityBlockingQueue

Summary:

  • public class PriorityBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, java.io.Serializable 
  • 本类与普通的PriorityBlockingQueue类中的方法基本一致,区别在于本类的方法都会在方法执行前先加锁执行完再解锁;
  • add、put会调用notEmpty.signal();唤醒等待的线程
  • take如果遇到队列为空则;调用await()方法,阻塞知道被唤醒

Fields:

private final ReentrantLock lock; //锁
private final Condition notEmpty; //条件锁,用于队列为空时阻塞
private transient volatile int allocationSpinLock;

private transient Comparator<? super E> comparator; //比较器
private transient Object[] queue;

Constructor:

public PriorityBlockingQueue(int initialCapacity,Comparator<? super E> comparator) {
        if (initialCapacity < 1)
            throw new IllegalArgumentException();
        this.lock = new ReentrantLock();
        this.notEmpty = lock.newCondition();
        this.comparator = comparator;
        this.queue = new Object[initialCapacity];
}

put&add

//该方法会阻塞,添加成功返回true,否则爆出异常
//添加成功会触发notEmpty.signal();使得原本在读取数据时阻塞的线程能够解除阻塞
public void put(E e) {
        offer(e); 
}
public boolean add(E e) {
        return offer(e);
}
public boolean offer(E e) {
        if (e == null)
            throw new NullPointerException();
        final ReentrantLock lock = this.lock;
        lock.lock(); //此处上锁,所以offer方法会产生阻塞
        int n, cap;
        Object[] array;
        while ((n = size) >= (cap = (array = queue).length))
            tryGrow(array, cap);   //扩容,直到扩容成功才退出循环,注意这里扩容的工作并不一定是本线程完成的,具体原因看扩容方法tryGrow
        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;
}

take

//从队列中读取一个数据,如果队列没有数据则阻塞
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;
        }
}

poll

//该方法只是尝试去从队列中获取第一个数,如果没有则返回null
public E poll() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return dequeue();
        } finally {
            lock.unlock();
        }
}

扩容操作;

该操作先释放锁;最后再尝试获取锁
然后很多线可能都来请求扩容,先进行CAS操作判断当前是否只有自己一个线程在扩容;
如果是则正常情况扩容;
不是则直到只有自己一个线程再去正常扩容;
正常库容还会判断自己是否是第一次在这里扩容,如果不是则不操作System.arraycopy()
private void tryGrow(Object[] array, int oldCap) {
        lock.unlock(); //先释放锁
        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);
        }
}

UNSAFE

上面出现的UNSAFE是一种非阻塞同步机制;
大概意思就是先操作,如果达不到预期目的再操作一次,直到成功为止;
CAS操作;只有通过bootstrap ClassLoader加载的class才能访问它;
    // Unsafe mechanics
    private static final sun.misc.Unsafe UNSAFE;
    private static final long allocationSpinLockOffset;
    static {
        try {
            UNSAFE = sun.misc.Unsafe.getUnsafe();
            Class<?> k = PriorityBlockingQueue.class;
            allocationSpinLockOffset = UNSAFE.objectFieldOffset
                (k.getDeclaredField("allocationSpinLock"));
        } catch (Exception e) {
            throw new Error(e);
        }
}




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