Java之集合(二十二)PriorityBlockingQueue
转载请注明源出处:http://www.cnblogs.com/lighten/p/7510799.html
1.前言
本章介绍阻塞队列PriorityBlockingQueue。这是一个无界有序的阻塞队列,排序规则和之前介绍的PriorityQueue一致,只是增加了阻塞操作。同样的该队列不支持插入null元素,同时不支持插入非comparable的对象。它的迭代器并不保证队列保持任何特定的顺序,如果想要顺序遍历,考虑使用Arrays.sort(pq.toArray())。该类不保证同等优先级的元素顺序,如果你想要强制顺序,就需要考虑自定义顺序或者是Comparator使用第二个比较属性。
2.PriorityBlockingQueue
2.1 数据结构
DEFAULT_INITIAL_CAPACITY:默认队列容量11
MAX_ARRAY_SIZE:最大可分配队列容量Integer.MAX_VALUE - 8,减8是因为有的VM实现在数组头有些内容
queue:队列元素数组。平衡二叉堆实现,父节点下标是n,左节点则是2n+1,右节点是2n+2。最小的元素在最前面
size:当前队列中元素的个数
comparator:决定队列中元素先后顺序的比较器
lock:所有public方法的锁
notEmpty:队列为空时的阻塞条件
allocationSpinLock:扩容数组分配资源时的自旋锁,CAS需要
q:PriorityQueue只用于序列化的时候,为了兼容之前的版本。只有在序列化和反序列化的时候不为null。
2.2 基本操作
放入一个元素:
和PriorityQueue的实现基本一致区别就是在于加锁了,并发出了非空信号唤醒阻塞的获取线程。具体操作原理看:PriorityQueue。这里值得一说的就是tryGrow的实现,其用了一个while循环来处理,下面是具体实现。
其先放开了锁,然后通过CAS设置allocationSpinLock来判断哪个线程获得了扩容权限,如果没抢到权限就会让出CPU使用权。最后还是要锁住开始真正的扩容。扩容权限争取到了就是计算大小,分配数组。暂不肯定为什么这么麻烦要分配数组的时候释放锁,暂猜测这样做效率会更高。
其它的操作过程都和PriorityQueue的类似,不再进行介绍。