构造方法
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
空参构造方法,也就是说没有传入大小,队列的大小默认为Integer的最大值
属性
private final int capacity;//容量
private final AtomicInteger count = new AtomicInteger();//存储的元素个数
transient Node<E> head;
private transient Node<E> last;
private final ReentrantLock takeLock = new ReentrantLock();
private final Condition notEmpty = takeLock.newCondition();
private final ReentrantLock putLock = new ReentrantLock();
private final Condition notFull = putLock.newCondition();
对于LinedBlockingQueue 存储数据不在是基于数组,而是基于Node 节点组成的链表
同时使用了两把锁,和两个 Condition ,这就说明相对于ArrayBlockingQueue,LinedBlockingQueue 的并发度更高,因为支持两把锁
put()
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
int c = -1;
// 当put一个元素的时候,先将这个元素封装为一个Node节点
Node<E> node = new Node<E>(e);
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
// 上锁,添加元素的锁
putLock.lockInterruptibly();
try {
//如果元素个数 == 最大容量,阻塞当前线程
while (count.get() == capacity) {
notFull.await();
}
//添加node
enqueue(node);
c = count.getAndIncrement();
if (c + 1 < capacity)//如果c+1 小于最大容量
notFull.signal();//唤醒等待put()的线程
} finally {
putLock.unlock();
}
if (c == 0)
signalNotEmpty();
}
take()
public E take() throws InterruptedException {
E x;
int c = -1;
//获取当前队列的元素个数
final AtomicInteger count = this.count;
final ReentrantLock takeLock = this.takeLock;
//上take对应的锁
takeLock.lockInterruptibly();
try {
//如果队列里面一个元素也没有,阻塞当前队列
while (count.get() == 0) {
notEmpty.await();
}
//将当前元素移除队列
x = dequeue();
//队列元素个数--
c = count.getAndDecrement();
if (c > 1)//如果队列还有元素,唤醒阻塞的take()线程
notEmpty.signal();
} finally {
takeLock.unlock();
}
if (c == capacity)
signalNotFull();
return x;
}
总结
LinedBlockingQueue 相比ArrayBrockingQueue 并发度更高,因为支持两把锁
LinedBlockingQueue 其实也是一个有界队列,只是如果没有传入大小,队列默认的大小为Integer的最大值