ArrayBlockingQueue的使用及源码解析
入队方法演示
- add
- offer
- put
public static void main(String[] args) throws InterruptedException {
ArrayBlockingQueue<Integer> arrayBlockingQueue = new ArrayBlockingQueue<>(3);
for (int i = 0;i < 4;i++){
arrayBlockingQueue.add(i);
}
System.out.println("执行到了");
}
队列的大小定义为3,使用add向其中添加4个元素,超出队列的最大值会报错
Exception in thread “main” java.lang.IllegalStateException: Queue full
at java.util.AbstractQueue.add(AbstractQueue.java:98)
at java.util.concurrent.ArrayBlockingQueue.add(ArrayBlockingQueue.java:312)
at com.strawberry.ArrayBlockingQueueExample.main(ArrayBlockingQueueExample.java:20)
public static void main(String[] args) throws InterruptedException {
ArrayBlockingQueue<Integer> arrayBlockingQueue = new ArrayBlockingQueue<>(3);
for (int i = 0;i < 4;i++){
arrayBlockingQueue.offer(i);
}
System.out.println("执行到了");
long now = System.currentTimeMillis();
//此处添加不进去,但是会停留5s
arrayBlockingQueue.offer(10,5,TimeUnit.SECONDS);
System.out.println("花费时间:" + (System.currentTimeMillis() - now) + "去打印下一个offer");
}
输出结果:
执行到了
花费时间:5009去打印下一个offer
public static void main(String[] args) throws InterruptedException {
ArrayBlockingQueue<Integer> arrayBlockingQueue = new ArrayBlockingQueue<>(3);
for (int i = 0;i < 4;i++){
arrayBlockingQueue.put(i);
}
System.out.println("执行到了");
}
put方法,当队列大小只要3,但是添加的值有4个,会一直阻塞,直到可以添加
出队方法演示
- remove
- poll
- take
public static void main(String[] args) throws InterruptedException {
ArrayBlockingQueue<Integer> arrayBlockingQueue = new ArrayBlockingQueue<>(3);
//添加2个元素
for (int i = 0;i < 2;i++){
arrayBlockingQueue.put(i);
}
//移除元素
boolean a = arrayBlockingQueue.remove(0);
//弹出元素
Integer poll = arrayBlockingQueue.poll();
System.out.println("a:" + a);
System.out.println("poll:" + poll);
//此处阻塞
Integer take = arrayBlockingQueue.take();
System.out.println("take" + take);
}
输出:
a:true
poll:1
线程阻塞在take那里
源码解析
成员变量
/** 存储队列的数组 */
final Object[] items;
/** 获取元素的下标 */
int takeIndex;
/** 添加元素的下标 */
int putIndex;
/** 队列元素个数 */
int count;
/** 全局锁 */
final ReentrantLock lock;
/** 等待出队的条件 消费者监视器 */
private final Condition notEmpty;
/** 等待入队的条件 生产者监视器 */
private final Condition notFull;
入队
public boolean add(E e) {
return super.add(e);
}
// AbstractQueue 调用offer(e)如果成功返回true,如果失败抛出异常
public boolean add(E e) {
if (offer(e))
return true;
else
throw new IllegalStateException("Queue full");
}
public boolean offer(E e) {
// 元素不可为空
checkNotNull(e);
final ReentrantLock lock = this.lock;
// 加锁
lock.lock();
try {
// 如果数组满了就返回false
if (count == items.length)
return false;
else {
enqueue(e);// 如果数组没满就调用入队方法并返回true
return true;
}
} finally {
//释放锁
lock.unlock();
}
}
public void put(E e) throws InterruptedException {
checkNotNull(e);
final ReentrantLock lock = this.lock;
// 加锁,如果线程中断了抛出异常
lock.lockInterruptibly();
try {
// 这里之所以使用while而不是if,是因为有可能多个线程阻塞在lock上,即使唤醒了可能其它线程先一步修改了队列又变成满的了,因此必须重新判断,再次等待
while (count == items.length)// 如果数组满了,使用notFull等待
notFull.await();// notFull等待表示现在队列满了,等待被唤醒(只有取走一个元素后,队列才不满)
enqueue(e);// 入队
} finally {
lock.unlock();
}
}
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 {
// 如果数组满了,就阻塞nanos纳秒,如果唤醒这个线程时依然没有空间且时间到了就返回false
while (count == items.length) {
if (nanos <= 0)
return false;
nanos = notFull.awaitNanos(nanos);
}
//入队
enqueue(e);
return true;
} finally {
lock.unlock();
}
}
private void enqueue(E x) {
final Object[] items = this.items;
// 把元素直接放在放指针的位置上
items[putIndex] = x;
// 如果放指针到数组尽头了,就返回头部
if (++putIndex == items.length)
putIndex = 0;
// 数量加1
count++;
// 唤醒notEmpty,因为入队了一个元素,所以肯定不为空了
notEmpty.signal();
}
出队
public E remove() {
// 调用poll()方法出队
E x = poll();
// 如果有元素出队就返回这个元素
if (x != null)
return x;
else
// 如果没有元素出队就抛出异常
throw new NoSuchElementException();
}
public E poll() {
final ReentrantLock lock = this.lock;
// 加锁
lock.lock();
try {
// 如果队列没有元素则返回null,否则出队
return (count == 0) ? null : dequeue();
} finally {
//释放锁
lock.unlock();
}
}
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
// 如果队列无元素,则阻塞等待在条件notEmpty上
while (count == 0)
notEmpty.await();
// 有元素了再出队
return dequeue();
} finally {
//释放锁
lock.unlock();
}
}
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
// 如果队列无元素,则阻塞等待nanos纳秒
// 如果下一次这个线程获得了锁但队列依然无元素且已超时就返回null
while (count == 0) {
if (nanos <= 0)
return null;
nanos = notEmpty.awaitNanos(nanos);
}
return dequeue();
} finally {
lock.unlock();
}
}
private E dequeue() {
final Object[] items = this.items;
// 取出指针位置的元素
@SuppressWarnings("unchecked")
E x = (E) items[takeIndex];
// 把取指针位置设为null
items[takeIndex] = null;
// 将指针前移,如果数组到头了就返回数组前端循环利用
if (++takeIndex == items.length)
takeIndex = 0;
// 元素数量减1
count--;
if (itrs != null)
itrs.elementDequeued();
// 唤醒notFull条件
notFull.signal();
return x;
}