arrayBlockQueue
生成(插入元素)
在往队列中插入数据由下面几个函数,他们的区别就是对队列满的情况处理不同
- put 一直等待着
- offer(无时间) 如果空了直接返回false
- offer(有时间) 等待指定的时间,在指定时间内如果空了,那么插入,负责返回false
- add 抛出一个IllegalStateException异常
首先来看put实现
public void put(E e) throws InterruptedException {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length)
notFull.await();
insert(e);
} finally {
lock.unlock();
}
}
首先需要获取锁,并把锁设置成可中断的。 然后判断是不是有空闲(count == items.length表示满了),如果没有空闲的空间,就通过await()一直等待着。 一直到有空闲了,通过insert进行插入。因为使用了可重入的锁,需要unlock解锁
然后我们来看下insert的实现
private void insert(E x) {
items[putIndex] = x;
putIndex = inc(putIndex);
++count;
notEmpty.signal();
}
把元素放到队列的最后面,对应的下标+1,数量也+1,最后通过signal通知其他线程有空闲的了
再来看下offer(无时间的)
public boolean offer(E e) {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count == items.length)
return false;
else {
insert(e);
return true;
}
} finally {
lock.unlock();
}
}
很简单,就看是否有空,没有空的直接返回false,否则就插入并返回true
然后来看看有时间版本的offer
public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException {
checkNotNull(e);
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length) {
if (nanos <= 0)
return false;
nanos = notFull.awaitNanos(nanos);
}
insert(e);
return true;
} finally {
lock.unlock();
}
}
当没有空间的时候,就等待指定的时间,如果等待时间到了还没有空,返回false,否则就插入并返回true
消费(移除元素)
同样消费也有好几个版本的,他们的区别也都是对队列是空的情况的处理
- take
- poll(有时间)
- poll(没有时间)
我们看下take
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
notEmpty.await();
return extract();
} finally {
lock.unlock();
}
}
如果队列是空的,那么一直等着,知道有元素可以消费,然后调用extract进行消费,同样最后需要释放锁
我们在看下extract的实现
private E extract() {
final Object[] items = this.items;
E x = this.<E>cast(items[takeIndex]);
items[takeIndex] = null;
takeIndex = inc(takeIndex);
--count;
notFull.signal();
return x;
}
把队列尾部的数据拿出来,尾部往前面挪动下,数据-1,最后通知其他线程队列有空的了
然后看下没有时间版本的poll
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (count == 0) ? null : extract();
} finally {
lock.unlock();
}
}
如果空的,就直接但会空的了
有时间版本的poll
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0) {
if (nanos <= 0)
return null;
nanos = notEmpty.awaitNanos(nanos);
}
return extract();
} finally {
lock.unlock();
}
}
这个如果是空的,那么就等待设置的时间,时间到了还没有就返回空的