ArrayBlockingQueue底层使用了一个数组来实现队列,阻塞的实现使用了ReentrantLock
常用的方法
1、入队操作
-
add(E): 如果满了,扔异常,数据丢弃
-
offer(E): 入队成功返回true,入队失败返回false,数据被丢弃
-
put(E): 入队失败线程挂起,直到入队成功
-
offer(E,time,unit): 入队失败线程等待指定时间返回false,数据丢弃
2、出队操作
-
remove():出队失败抛出异常
-
poll():出队失败返回null
-
take():出队失败一直挂起,直到有元素出队
-
poll(time,unit):出队失败等待指定时间后返回null
使用案例
package com.zjw.juc;
import java.util.Arrays;
import java.util.Scanner;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;
public class ArrayBlockingQueueDemo {
public static void main(String[] args) throws Exception {
// capacity为数组长度,同时也是队列长度
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(5);
for (; ; ) {
Scanner scanner = new Scanner(System.in);
String command = scanner.nextLine().trim();
if ("exit".equals(command) || "quit".equals(command)) {
break;
}
String[] commands = command.split("\\s+");
switch (commands[0]) {
case "add":
try {
queue.add(commands[1]);
} catch (Exception e) {
System.out.println("当队列满时抛出异常: " + e.getMessage());
}
break;
case "offer":
if (commands.length == 3) {
boolean ret = queue.offer(commands[1], Integer.parseInt(commands[2]), TimeUnit.MILLISECONDS);
if (!ret) {
System.out.println("队列满,间隔" + commands[2] + "ms之后返回");
}
} else {
boolean ret = queue.offer(commands[1]);
if (!ret) {
System.out.println("队列满,返回 false");
} else {
System.out.println("队列未满,返回 true");
}
}
break;
case "put":
System.out.println("put 当队列满时会一直阻塞,直到放入数据成功.");
queue.put(commands[1]);
break;
case "remove":
if (commands.length == 2) {
boolean ret = queue.remove(commands[1]);
System.out.println("删除" + commands[1] + "元素返回结果: " + ret);
} else {
try {
queue.remove();
} catch (Exception e) {
System.out.println("删除数据失败,抛出异常: " + e.getMessage());
}
}
break;
case "poll":
if (commands.length == 2) {
String ret = queue.poll(Integer.parseInt(commands[1]), TimeUnit.MILLISECONDS);
if (ret == null) {
System.out.println("队列为空,阻塞" + commands[1] + "ms后返回null");
}
} else {
String ret = queue.poll();
System.out.println("poll 返回: " + ret);
}
break;
case "take":
System.out.println("take操作当队列没有数据时会一直阻塞.");
queue.take();
break;
}
System.out.println(Arrays.asList(queue.toArray()));
}
}
}
源码分析
add(E)
public boolean add(E e) {
// 调用super(AbstractQueue)的add方法
return super.add(e);
}
public boolean add(E e) {
// 直接调用offer方法,如果offer调用成功直接返回true,否则抛异常
if (offer(e))
return true;
else
throw new IllegalStateException("Queue full");
}
public boolean offer(E e) {
// 检查元素是否为null,如果为null直接抛异常
checkNotNull(e);
// 获取ReentrantLock,并加锁
final ReentrantLock lock = this.lock;
lock.lock();
try {
// 队列满,返回false
if (count == items.length)
return false;
else {
// 入队操作
enqueue(e);
return true;
}
} finally {
// 释放ReentrantLock
lock.unlock();
}
}
private void enqueue(E x) {
final Object[] items = this.items;
// 入队
items[putIndex] = x;
// 对齐游标,可以思考为循环队列 putIndex = (putIndex + 1) % items.length
if (++putIndex == items.length)
putIndex = 0;
count++;
// 唤醒因为队列空而阻塞的线程
notEmpty.signal();
}
offer(E)
public boolean offer(E e) {
// 检查元素是否为null,如果为null直接抛异常
checkNotNull(e);
// 获取ReentrantLock,并加锁
final ReentrantLock lock = this.lock;
lock.lock();
try {
// 队列满,返回false
if (count == items.length)
return false;
else {
// 入队操作
enqueue(e);
return true;
}
} finally {
// 释放ReentrantLock
lock.unlock();
}
}
offer(E, timeout, TimeUnit)
public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException {
// 检查元素不能为null,为null会跑出异常NullPointerException
checkNotNull(e);
long nanos = unit.toNanos(timeout);
// 获取可中断锁
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
// 指定有限时间等待,时间到了会自动醒过来进行循环判断,最终会使nanos<=0条件成立,返回false
while (count == items.length) {
if (nanos <= 0)
return false;
nanos = notFull.awaitNanos(nanos);
}
// 元素入队
enqueue(e);
return true;
} finally {
// 释放锁
lock.unlock();
}
}
put(E)
public void put(E e) throws InterruptedException {
// 检查元素不能为null,为null会跑出异常NullPointerException
checkNotNull(e);
// 获取可中断锁
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
// 如果队列满了,会一直等待,直到被唤醒
while (count == items.length)
notFull.await();
// 入队操作
enqueue(e);
} finally {
lock.unlock();
}
}
remove()
public E remove() {
// 调用poll获取元素,如果没有获取到跑出异常NoSuchElementException
E x = poll();
if (x != null)
return x; // 获取到了直接返回
else
throw new NoSuchElementException();
}
poll()
public E poll() {
// 加锁
final ReentrantLock lock = this.lock;
lock.lock();
try {
// 如果队列空返回null,否则进行出队操作,并返回出队结果
return (count == 0) ? null : dequeue();
} finally {
// 释放锁
lock.unlock();
}
}
private E dequeue() {
final Object[] items = this.items;
// 获取take的数据
E x = (E) items[takeIndex];
// 擦除数据,防止误操作越界读取到数据,同时可以帮助GC
items[takeIndex] = null;
// takeIndex的对齐操作 takeIndex = (takeIndex + 1) % items.length
if (++takeIndex == items.length)
takeIndex = 0;
// 队列元素--
count--;
// 迭代器相关操作
if (itrs != null)
itrs.elementDequeued();
// 唤醒因为入队操作阻塞的线程
notFull.signal();
return x;
}
take()
public E take() throws InterruptedException {
// 获取可中断锁
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
// 如果队列空,则进入等待
while (count == 0)
notEmpty.await();
// 出队操作
return dequeue();
} finally {
// 释放锁
lock.unlock();
}
}
poll(time, unit)
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
// 时间转换
long nanos = unit.toNanos(timeout);
// 获取可中断锁
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
// 如果队列空则等待指定时间之后返回,如果后一次循环检查nanos<0 则会直接返回null,不会走到dequeue()
while (count == 0) {
if (nanos <= 0)
return null;
nanos = notEmpty.awaitNanos(nanos);
}
// 出队操作
return dequeue();
} finally {
lock.unlock();
}
}