介绍
可选有界阻塞队列基于链表,该队列遵循FIFO。存入队尾,取出队首。
使用
使用较简单就不介绍了。
源码解析
- ReentrantLock+Condition原理
两个ReentrantLock两个Condition
//取锁,控制取数据
private final ReentrantLock takeLock = new ReentrantLock();
//取等待,存唤醒
private final Condition notEmpty = takeLock.newCondition();
//存锁,控制存数据
private final ReentrantLock putLock = new ReentrantLock();
//存等待,取唤醒
private final Condition notFull = putLock.newCondition();
- offer(E e)
如果容量已满,则返回false,添加失败;如果是第一次添加则会唤醒一个等待中的取数据;如果添加数据中,还有容量则会以传播的形式唤醒等待中的存数据
public boolean offer(E e) {
if (e == null) throw new NullPointerException();
final AtomicInteger count = this.count;
//容量满,返回false
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);
//结点个数+1,但是c是原值
c = count.getAndIncrement();
//如果容量未满,因为存取使用的是各自独立的锁;所以如果出现数据存储,多次等待的情况下,取数据又取了多次(只有在容量边缘的时候才会唤醒一次),之后通过offer加了数据,这时候会以传播的形式唤醒剩余的等待,知道容量满了
if (c + 1 < capacity)
notFull.signal();
}
} finally {
putLock.unlock();
}
//如果数据是第一次存入,则会唤醒等待中的取数据操作
if (c == 0)
signalNotEmpty();
return c >= 0;
}
- offer(E e, long timeout, TimeUnit unit)
和offer原理一样,唯一的区别是等待的时间是timeout,不是无限的
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 {
while (count.get() == capacity) {
if (nanos <= 0)
return false;
nanos = notFull.awaitNanos(nanos);
}
enqueue(new Node<E>(e));
c = count.getAndIncrement();
if (c + 1 < capacity)
notFull.signal();
} finally {
putLock.unlock();
}
if (c == 0)
signalNotEmpty();
return true;
}
- put(E e)
和offer原理一样,唯一的区别是,如果容量已满,则put会等待
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);
c = count.getAndIncrement();
if (c + 1 < capacity)
notFull.signal();
} finally {
putLock.unlock();
}
if (c == 0)
signalNotEmpty();
}
- poll()
取队尾数据,如果没有容量已满,则返回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;
}
- take()
和poll原理一样,唯一的区别是如果没有数据take会等待,直到有数据;
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;
}
- poll(long timeout, TimeUnit unit)
和poll原理一样,唯一的区别是等待的时间是timeout,不是无限的
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();
c = count.getAndDecrement();
if (c > 1)
notEmpty.signal();
} finally {
takeLock.unlock();
}
if (c == capacity)
signalNotFull();
return x;
}