1- 需求背景
最近项目中有这样一个需求,因为在恢复WAL的过程中,以前是把WAL文件中的记录顺序的读出来,插入到阻塞队列(LinkedBlockingQueue)中,供消费端消费。后来发现顺序读取多个WAL文件插入队列的方式太慢,考虑使用并行WAL文件读取的方式,但是在插入队列时需要保证记录出队列时保持有序,于是考虑把LinkedBlockingQueue改成PriorityQueue,使用记录的id作为优先级完成有序出队列,但是发现PriorityQueue不是线程安全的,于是找到了PriorityBlockingQueue,说是阻塞的,但是发现提供的几个入队方法都是非阻塞的。那么问题来了,我们需要一个:
- 阻塞的
- 线程安全的
- 顺序出队列的
于是考虑封装PriorityBlockingQueue
2- LinkedBlockingQueue源码分析
2-1 重要成员变量
用来存储队列中的元素,是个模板类
/**
* Linked list node class
*/
static class Node<E> {
E item;
Node<E> next;
Node(E x) { item = x; }
}
其他成员变量,就不一一解释了,代码中给出了明确的解释,下边分析方法时会进一步解释
private final int capacity;//总大小,队列元素个数不能超过这个总大小
/** Current number of elements */
private final AtomicInteger count = new AtomicInteger();
/**
* Head of linked list.
* Invariant: head.item == null
*/
transient Node<E> head;
/**
* Tail of linked list.
* Invariant: last.next == null
*/
private transient Node<E> last;
/** Lock held by take, poll, etc */
private final ReentrantLock takeLock = new ReentrantLock();
/** Wait queue for waiting takes */
private final Condition notEmpty = takeLock.newCondition();
/** Lock held by put, offer, etc */
private final ReentrantLock putLock = new ReentrantLock();
/** Wait queue for waiting puts */
private final Condition notFull = putLock.newCondition();
2-2 插入方法
put(E e): 阻塞插入方法
offer(E e, long timeout, TimeUnit unit):非阻塞插入方法,但是会等待一个超时时间,超时才返回false
boolean offer(E e):非阻塞插入方法,不等待超时,如果不能插入就返回false
2-2-1 put方法
原型:public void put(E e) throws InterruptedException
这是一个阻塞方法,如果队列满了,就等待
if (e == nu