简介
阻塞队列在应用广泛,例如线程池。其原理就是用了锁机制。
API规范
API | 1 | 2 | 容量到达限制阻塞(阻塞队列使用核心) |
---|---|---|---|
插入 | add()(到达容量阻塞) | offer() (返回添加成功与否) | put() |
移除 | remove() (返回移除成功与否) | poll() (返回移除的元素) | take() |
原理
这里以ArrayBlockingQueue为例
add和remove
add
public boolean add(E e) {
//调用了父类的add
return super.add(e);
}
public boolean add(E e) {
//很简单,尝试插入,成功为true,否则抛出异常
if (offer(e))
return true;
else
throw new IllegalStateException("Queue full");
}
remove
public boolean remove(Object o) {
if (o == null) return false;
final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count > 0) {
final int putIndex = this.putIndex;
int i = takeIndex;
do {
if (o.equals(items[i])) {
removeAt(i);
//成功移除返回true
return true;
}
if (++i == items.length)
i = 0;
} while (i != putIndex);
}
//移除失败返回false
return false;
} finally {
lock.unlock();
}
}
offer和poll
offer
public boolean offer(E e) {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count == items.length)
//到达总长度就添加失败
return false;
else {
enqueue(e);
//否则就成功
return true;
}
} finally {
lock.unlock();
}
}
poll
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
//这里调用了dequeue()
return (count == 0) ? null : dequeue();
} finally {
lock.unlock();
}
}
private E dequeue() {
final Object[] items = this.items;
@SuppressWarnings("unchecked")
//获取需要的节点
E x = (E) items[takeIndex];
items[takeIndex] = null;
if (++takeIndex == items.length)
takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
//这里是给put和take用的
notFull.signal();
//将前面获取的节点返回
return x;
}
put和take
put
public void put(E e) throws InterruptedException {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length)
//如果满了就阻塞
notFull.await();
enqueue(e);
} finally {
lock.unlock();
}
}
take
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
//如果队列为空就阻塞
notEmpty.await();
return dequeue();
} finally {
lock.unlock();
}
}