官方给出的代码如下:
class FIFOEntry<E extends Comparable super E>>
implements Comparable<FIFOEntry<E>> {
static final AtomicLong seq = new AtomicLong(0);
final long seqNum;
final E entry;
public FIFOEntry(E entry) {
seqNum = seq.getAndIncrement();
this.entry = entry;
}
public E getEntry() { return entry; }
public int compareTo(FIFOEntry other) {
int res = entry.compareTo(other.entry);
if (res == 0 && other.entry != this.entry)
res = (seqNum < other.seqNum ? -1 : 1);
return res;
}
}
method | Throws Exception | Special Value | Blocks | Times Out |
---|---|---|---|---|
Insert | put(o),offer(o),add(o) | |||
Remove | poll(),remove(o) | take() | poll(t) | |
Examine | peek() |
请注意PriorityBlockingQueue的返回值情况。
* 由于PriorityBlockingQueue队列可以自动扩容,所以插入元素时,不用等待阻塞。
* 获取元素时,若队列为空,需要阻塞等待。
// 数组的默认容量大小
private static final int DEFAULT_INITIAL_CAPACITY = 11;
// 数组的最大容量,源码注释:有的虚拟机可能会使用数组的头部一个字节。
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
// 数组,节点queue[n]的儿子节点是 queue[2*n+1]和queue[2*(n+1)]。
// 注:最小堆的定义和使用,详细见《算法导论》
private transient Object[] queue;
// 队列中元素的个数
private transient int size;
// 比较器,用来排序
private transient Comparator super E> comparator;
// 对操作进行同步的锁
private final ReentrantLock lock;
// 基于锁的条件变量
private final Condition notEmpty;
// 自旋锁,在分配新的空间时进行同步
private transient volatile int allocationSpinLock;
// 优先队列变量,用来向前兼容
private PriorityQueue q;
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(Collection extends E> c) {
this.lock = new ReentrantLock();
this.notEmpty = lock.newCondition();
boolean heapify = true; // true if not known to be in heap order
boolean screen = true; // true if must screen for nulls
// 若参数集合c是SortedSet类型,不需要堆化
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类型的,也不需要堆化
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[]数组中,然后对该数组进行堆化
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)
heapify();
}
private static 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;
}
private static 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;
// 若右边的索引数小于元素个数,且左边的大于右边的儿子节点的值
// 把右边的儿子节点的值赋给变量c
if (right < n &&
((Comparable super T>) c).compareTo((T) array[right]) > 0)
c = array[child = right];
// 若插入的值小于c,k应该作为父节点,否则k应该作为儿子节点
if (key.compareTo((T) c) <= 0)
break;
// c是父节点
array[k] = c;
k = child;
}
// 插入的值作为父节点
array[k] = key;
}
}
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 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);
}
}
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;
}
public void put(E e) {
offer(e); // never need to block
}
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);
// 把元素e插入,并进行堆化
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;
}
public boolean add(E e) {
return offer(e);
}
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return dequeue();
} finally {
lock.unlock();
}
}
使用PriorityBlockingQueue编写的生产者消费者模型。
注意,生产者不会阻塞等待。
package BlockingQueue;
import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
class PutTask implements Runnable {
private BlockingQueue queue;
private Random r = new Random(1000);
PutTask(BlockingQueue q) {
queue = q;
}
public void run() {
while (true) {
try {
Thread.sleep(2);
String value = Integer.toString(r.nextInt(1000));
queue.put(value);
System.out.println(Thread.currentThread().getName() + " put value: " + value);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class DealTask implements Runnable {
private BlockingQueue queue;
private Random r = new Random(10000);
DealTask(BlockingQueue q) {
queue = q;
}
public void run() {
while (true) {
try {
Thread.sleep(3);
String o = (String) queue.take();
System.out.println(Thread.currentThread().getName() + " get value: " + o);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public class DoPriorityBQ {
public static void main(String[] args) {
final BlockingQueue q = new PriorityBlockingQueue(1000);
new Thread(new PutTask(q), "producer3").start();
new Thread(new DealTask(q), "consumer2").start();
new Thread(new DealTask(q), "consumer1").start();
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
以下程序测试优先阻塞队列的排序功能。
package BlockingQueue;
import java.util.Random;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
public class DoPriorityBQ2 {
public static void main(String[] args) throws InterruptedException {
final BlockingQueue queue = new PriorityBlockingQueue(10);
Random r = new Random(100);
for (int i = 0; i < 10; i++) {
int vi = r.nextInt(100);
System.out.print(" " + vi);
queue.put(vi);
}
System.out.println("\n");
Integer v;
while ((v = queue.take()) != null) {
System.out.print(" " + String.valueOf(v));
}
}
}
程序解读:
* 该程序会先在队列中插入一些随机数,然后再每次取队列的头节点元素,并输出。
* 可以看到,输出的结果是排好序的。
* 该程序没有使用多线程,主要是为了测试程序的排序功能。