PriorityBlockingQueue
特点
- 这是一个优先级队列,该队列中的元素必须是Compartor或者Comparable的实现类才可以;
- 这是一个无界队列,所以入队不需要等待,直接将元素写入即可,出队时如果队列中没有元素需要在Condition上等待,这样也说明了该队列只需要一个Condition即可;
- 该类的底层使用的是数组,成员变量有最大容量的最大值为Integer.MAX_VALUE,但在该类初始化数组的时候并没有判断最大值,所以数组的大小还是可以大于该值,但如果在写入元素时因为内存不够等问题,会抛出OOM异常。
- 底层数据结构使用的是小根堆和大根堆,即最小值或者最大值(优先级最高)的元素排在根部,每次取出元素时只需要获取根部元素即可,然后再对剩余的元素重新排序
基本结构
off(E e)
入队操作,需要加锁,不支持中断操作,因为是无界队列,所以不需要Condition等待条件
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;
}
- 如果e为null,则抛出NPE
- 获取ReentrantLock并加锁,这是一个非中断锁
- 将size赋值给n,queue赋值给array获取array的长度赋值给cap,如果n大于等于了cap说明数组的元素个数大于等于了数组的长度需要进行扩容操作,调用tryGrow方法进行扩容
- 获取comparator比较器,如果为null使用默认比较器进行比较,调用siftUpComparable方法进行小顶堆的排序;如果不为null就使用指定的排序器进行排序并构造小顶堆
- 元素个数size+1操作
- 唤醒出队操作中等待的线程并返回true
- 最后进入finally代码块进行锁的释放
add(E e)
add操作其实调用的就是offer方法
public boolean add(E e) {
return offer(e);
}
put(E e)
put操作和add操作一样,都是直接调用offer方法
public void put(E e) {
offer(e); // never need to block
}
take(E e)
从优先队列中获取元素,如果元素为null,则在Condition队列上进行等待,直到队列中有元素
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;
}
- 获取ReentrantLock锁并加锁,该锁是支持中断操作
- 进入while循环,调用dequeue方法从队列中获取元素,如果为null,调用await方法进行等待;如果不为null,将该元素从队列中删除并重新构造小顶堆,返回该元素
- 进入finally代码块释放锁
poll
该方法也是从队列中获取元素,它和take的区别在于:
- 该方法加的锁是不支持中断操作的
- 调用dequeue方法获取元素,如果为null,直接返回,不进行等待
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return dequeue();
} finally {
lock.unlock();
}
}
peek
该方法也是获取元素,但只是获取,并不会将该元素从队列中移除
public E peek() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (size == 0) ? null : (E) queue[0];
} finally {
lock.unlock();
}
}
size
获取队列中元素的个数,这个变量和数组的长度不一定相等,该方法需要加锁,因为要防止在调用该方法时别的线程往该队列中写入元素
public int size() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return size;
} finally {
lock.unlock();
}
}

浙公网安备 33010602011771号