简介
LinkedBlockingQueue 字义为链式阻塞队列,既然是链式,那么内部肯定以链接结构存储了,相比ArrayBlockingQueue,可以是一个无界队列,但是性能比之要差。
初始化
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
public LinkedBlockingQueue(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
//链式头和尾 初始化
last = head = new Node<E>(null);
}
//数组初始化
public LinkedBlockingQueue(Collection<? extends E> c) {
//默认临界值
this(Integer.MAX_VALUE);
final ReentrantLock putLock = this.putLock;
putLock.lock(); // Never contended, but necessary for visibility
try {
int n = 0;
for (E e : c) {
if (e == null)
throw new NullPointerException();
if (n == capacity)
throw new IllegalStateException("Queue full");
enqueue(new Node<E>(e));
++n;
}
//计数器
count.set(n);
} finally {
putLock.unlock();
}
}
private void enqueue(Node<E> node) {
// assert putLock.isHeldByCurrentThread();
// assert last.next == null;
//设置尾节点
last = last.next = node;
}
入队
//入队操作使用putLock 出队使用lock 即两个是入队和出队使用的是不一样的锁
//可线程打断抛异常
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
int c = -1;
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();
}
//入队 设置尾节点
enqueue(node);
//计数器加1
c = count.getAndIncrement();
//达到临界值 不满条件通知,因为另一个线程有可能再出队
if (c + 1 < capacity)
notFull.signal();
} finally {
putLock.unlock();
}
if (c == 0)
signalNotEmpty();
}
//可过期入队 过期返回false
public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException {
if (e == null) throw new NullPointerException();
long nanos = unit.toNanos(timeout);
int c = -1;
final ReentrantLock putLock = this.putLock;
final AtomicInteger count = this.count;
putLock.lockInterruptibly();
try {
//循环判断 如果队列已满并且过期返回false
while (count.get() == capacity) {
if (nanos <= 0)
return false;
//阻塞
nanos = notFull.awaitNanos(nanos);
}
//入队
enqueue(new Node<E>(e));
//计数器+1
c = count.getAndIncrement();
//不满条件通知
if (c + 1 < capacity)
notFull.signal();
} finally {
putLock.unlock();
}
if (c == 0)
signalNotEmpty();
return true;
}
//入队,如果队列已满 则 返回false
public boolean offer(E e) {
if (e == null) throw new NullPointerException();
final AtomicInteger count = this.count;
if (count.get() == capacity)
return false;
int c = -1;
Node<E> node = new Node<E>(e);
final ReentrantLock putLock = this.putLock;
putLock.lock();
try {
//如果队列未满 则入队
if (count.get() < capacity) {
enqueue(node);
c = count.getAndIncrement();
//不满条件通知
if (c + 1 < capacity)
notFull.signal();
}
} finally {
putLock.unlock();
}
if (c == 0)
signalNotEmpty();
return c >= 0;
}
出队
//直到获取元素为止,打断抛异常
public E take() throws InterruptedException {
E x;
int c = -1;
final AtomicInteger count = this.count;
final ReentrantLock takeLock = this.takeLock;
takeLock.lockInterruptibly();
try {
//阻塞
while (count.get() == 0) {
notEmpty.await();
}
x = dequeue();
c = count.getAndDecrement();
if (c > 1)
notEmpty.signal();
} finally {
takeLock.unlock();
}
if (c == capacity)
signalNotFull();
return x;
}
//出队
private E dequeue() {
//让原先的head被gc回收 head设置为原先的next并且item设置为null
Node<E> h = head;
Node<E> first = h.next;
h.next = h;
head = first;
E x = first.item;
first.item = null;
return x;
}
//可一段时间内获取
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
E x = null;
int c = -1;
long nanos = unit.toNanos(timeout);
final AtomicInteger count = this.count;
final ReentrantLock takeLock = this.takeLock;
takeLock.lockInterruptibly();
try {
//在时间范围内循环获取元素
while (count.get() == 0) {
if (nanos <= 0)
return null;
nanos = notEmpty.awaitNanos(nanos);
}
//出队
x = dequeue();
//计数器-1
c = count.getAndDecrement();
//不空条件通知
if (c > 1)
notEmpty.signal();
} finally {
takeLock.unlock();
}
//不空条件通知
if (c == capacity)
signalNotFull();
return x;
}
//有就返回元素 没有就返回null
public E poll() {
final AtomicInteger count = this.count;
if (count.get() == 0)
return null;
E x = null;
int c = -1;
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
//队列未空
if (count.get() > 0) {
出队
x = dequeue();
c = count.getAndDecrement();
//不空条件通知
if (c > 1)
notEmpty.signal();
}
} finally {
takeLock.unlock();
}
//不空条件通知
if (c == capacity)
signalNotFull();
return x;
}
//获取元素 但是不移除
public E peek() {
if (count.get() == 0)
return null;
final ReentrantLock takeLock = this.takeLock;
takeLock.lock();
try {
//获取当前元素返回
Node<E> first = head.next;
if (first == null)
return null;
else
return first.item;
} finally {
takeLock.unlock();
}
}
//移除
public boolean remove(Object o) {
if (o == null) return false;
//出队、入队全锁
fullyLock();
try {
//从头部开始循环查找匹配元素
for (Node<E> trail = head, p = trail.next;
p != null;
trail = p, p = p.next) {
if (o.equals(p.item)) {
unlink(p, trail);
return true;
}
}
return false;
} finally {
//释放出队入队锁
fullyUnlock();
}
}
void unlink(Node<E> p, Node<E> trail) {
//去除p节点 用p.next 代替
p.item = null;
trail.next = p.next;
if (last == p)
last = trail;
//计数器-1 不满条件通知 这里有个疑问是:不需要判断 因为remove中使用了fullyLock 所以 移除一个 肯定是不满的
if (count.getAndDecrement() == capacity)
notFull.signal();
}
总结
如果是不确定数组大小的,则可以使用LinkedBlockingQueue(也可以指定),确定使用ArrayBlockingQueue