//A heap-based priority queue, which is unbounded. //Look at the constructor first: public PriorityBlockingQueue() { this(DEFAULT_INITIAL_CAPACITY, null); } 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]; } public PriorityBlockingQueue(int initialCapacity) { this(initialCapacity, null); } public PriorityBlockingQueue(Collection<? extends E> c) { this.lock = new ReentrantLock(); this.notEmpty = lock.newCondition(); //Does it need to be heaped boolean heapify = true; // true if not known to be in heap order //Do you need to check for null boolean screen = true; // true if must screen for nulls if (c instanceof SortedSet<?>) { SortedSet<? extends E> ss = (SortedSet<? extends E>) c; this.comparator = (Comparator<? super E>) ss.comparator(); heapify = false; } else if (c instanceof PriorityBlockingQueue<?>) { PriorityBlockingQueue<? extends E> pq = (PriorityBlockingQueue<? extends E>) c; this.comparator = (Comparator<? super E>) pq.comparator(); screen = false; if (pq.getClass() == PriorityBlockingQueue.class) // exact match heapify = false; } Object[] a = c.toArray(); int n = a.length; // If c.toArray incorrectly doesn't return Object[], copy it. if (a.getClass() != Object[].class) a = Arrays.copyOf(a, n, Object[].class); if (screen && (n == 1 || this.comparator != null)) { for (int i = 0; i < n; ++i) if (a[i] == null) throw new NullPointerException(); } this.queue = a; this.size = n; if (heapify) // generate heap heapify(); } //add element public boolean add(E e) { return offer(e); } //Add elements without blocking public boolean offer(E e) { if (e == null) throw new NullPointerException(); final ReentrantLock lock = this.lock; lock.lock(); int n, cap; Object[] array; //expand 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); //length+1 size = n + 1; //The current queue is not empty to wake up the thread waiting on notEmpty. notEmpty.signal(); } finally { lock.unlock(); } return true; } //Extend. The processing here is very delicate and uses CAS for expansion. private void tryGrow(Object[] array, int oldCap) { // here the lock is released lock.unlock(); // must release and then re-acquire main lock Object[] newArray = null; /** Use CAS to set the allocationSpinLock state and expand the capacity if it is successful. Note that although this code uses the CAS mechanism, it still has concurrency problems. The key is that the following sentence judges && queue == array The key is here, and it will only be copied if it is equal*/ 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 { // Set to 0 after expansion allocationSpinLock = 0; } } //Other threads are expanded and handed over to other threads for execution if (newArray == null) // back off if another thread is allocating Thread.yield(); lock.lock(); // The judgment of queue == array is very important. This judgment judges that only one thread is successfully expanded, and all other expansion threads fail. if (newArray != null && queue == array) { queue = newArray; System.arraycopy(array, 0, newArray, 0, oldCap); } } //Add elements without blocking public boolean offer(E e, long timeout, TimeUnit unit) { return offer(e); // never need to block } //Only get the header element without blocking public E peek() { final ReentrantLock lock = this.lock; lock.lock(); try { return (size == 0) ? null : (E) queue[0]; } finally { lock.unlock(); } } // get the header element and remove it 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]; 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; } } //Get and remove an element within a certain period of time public E poll(long timeout, TimeUnit unit) throws InterruptedException { long nanos = unit.toNanos(timeout); final ReentrantLock lock = this.lock; lock.lockInterruptibly(); E result; try { //When there are elements in the queue and there is no timeout, wait for the queue to become non-empty on the notEmpty condition. while ( (result = dequeue()) == null && nanos > 0) nanos = notEmpty.awaitNanos(nanos); } finally { lock.unlock(); } return result; } //The direct queue of blockable acquisition elements is not empty. 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; } //get queue size public int size() { final ReentrantLock lock = this.lock; lock.lock(); try { return size; } finally { lock.unlock(); } } //Unbounded queue so return the maximum value. public int remainingCapacity() { return Integer.MAX_VALUE; } // Returns the element's comparator public Comparator<? super E> comparator() { return comparator; } //return whether an element is included public boolean contains(Object o) { final ReentrantLock lock = this.lock; lock.lock(); try { return indexOf(o) != -1; } finally { lock.unlock(); } } private int indexOf(Object o) { if (o != null) { Object[] array = queue; int n = size; for (int i = 0; i < n; i++) if (o.equals(array[i])) return i; } return -1; } // delete an element public boolean remove(Object o) { final ReentrantLock lock = this.lock; lock.lock(); try { int i = indexOf(o); if (i == -1) return false; removeAt(i); return true; } finally { lock.unlock(); } } private void removeAt(int i) { Object[] array = queue; int n = size - 1; if (n == i) // removed last element array[i] = null; else { E moved = (E) array[n]; array[n] = null; Comparator<? super E> cmp = comparator; if (cmp == null) siftDownComparable(i, moved, array, n); else siftDownUsingComparator(i, moved, array, n, cmp); if (array[i] == moved) { if (cmp == null) siftUpComparable(i, moved, array); else siftUpUsingComparator(i, moved, array, cmp); } } size = n; } //convert to array public Object[] toArray() { final ReentrantLock lock = this.lock; lock.lock(); try { return Arrays.copyOf(queue, size); } finally { lock.unlock(); } } //Convert to typed array public <T> T[] toArray(T[] a) { final ReentrantLock lock = this.lock; lock.lock(); try { int n = size; //If the array length is less than the queue length, regenerate an array of queue length if (a.length < n) // Make a new array of a's runtime type, but my contents: return (T[]) Arrays.copyOf(queue, size, a.getClass()); System.arraycopy(queue, 0, a, 0, n); if (a.length > n) a[n] = null; return a; } finally { lock.unlock(); } } // clear the queue public void clear() { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] array = queue; int n = size; size = 0; for (int i = 0; i < n; i++) array[i] = null; } finally { lock.unlock(); } } //Remove all elements in the queue and encapsulate them into a collection public int drainTo (Collection <? super E> c) { return drainTo(c, Integer.MAX_VALUE); } public int drainTo (Collection <? super E> c, int maxElements) { if (c == null) throw new NullPointerException(); if (c == this) throw new IllegalArgumentException(); if (maxElements <= 0) return 0; final ReentrantLock lock = this.lock; lock.lock(); try { int n = Math.min(size, maxElements); for (int i = 0; i < n; i++) { c.add((E) queue[0]); // In this order, in case add() throws. dequeue(); } return n; } finally { lock.unlock(); } }
Read the PriorityBlocking source code
Guess you like
Origin http://43.154.161.224:23101/article/api/json?id=326311527&siteId=291194637
Recommended
Ranking