1、ArrayBlockingQueue特点:
a、底层数据结构是数组,Object[];
b、插入、读取操作都有加锁,线程安全;
c、有界队列,必须指定容量;
d、支持公平锁和非公平锁,构造参数可以指定;
2、常用方法及特点
2.1、构造方法
//构造1:仅指定容量
public ArrayBlockingQueue(int capacity) {
this(capacity, false);//调的还是构造2,默认使用的是非公平锁
}
//构造2:指定容量,指定是否使用公平锁
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = new Object[capacity];//可见其数据结构为数组
lock = new ReentrantLock(fair);//按参数锁类型构造锁对象
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
//构造3:指定容量,指定是否使用公平锁定,指定数据集合
public ArrayBlockingQueue(int capacity, boolean fair,
Collection<? extends E> c) {
this(capacity, fair);//调构造2
//处理初始数据放入
final ReentrantLock lock = this.lock;
lock.lock(); // Lock only for visibility, not mutual exclusion
try {
int i = 0;
try {
for (E e : c) {
checkNotNull(e);
items[i++] = e;
}
} catch (ArrayIndexOutOfBoundsException ex) {
throw new IllegalArgumentException();
}
count = i;
putIndex = (i == capacity) ? 0 : i;
} finally {
lock.unlock();
}
}
2.2、插入元素
a、add(E e)--当队列未满时,可以直接插入,返回true;如果队列满了,则会抛异常,整个过程会加锁、不会阻塞;
// 其调的父类AbstractQueue的add方法,本质是offer方法
// 加锁、不阻塞
// 队列满后再放入会抛异常:IllegalStateException("Queue full")
public boolean add(E e) {
return super.add(e);
}
b、offer(E e)--当队列未满时,可以直接插入,返回true;如果队列满了,不会抛异常,会返回false;整个过程会加锁、不会阻塞;
// 1、检查参数是否为空;
// 2、加锁;
// 3、看队列是否已满,满了则直接返回false,否则执行入队动作,然后返回true
// 4、finally会释放锁定
// 注意:add方法本质调的也是该方法
public boolean offer(E e) {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count == items.length)//判断队列是否已满
return false;
else {
enqueue(e);//入队,会根据putIndex赋值数组,修改数量
return true;
}
} finally {
lock.unlock();
}
}
c、offer(E e, long timeout, TimeUnit unit)--和方法b类似,只是增加了延时再试的逻辑,当队列满后,会等待指定的时间再试,如果此时未满了就插入元素,返回true,否则还是已满,则返回false;
// 增加了延时判断其他同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);
}
enqueue(e);
return true;
} finally {
lock.unlock();
}
}
d、put(E e)--当队列未满时,直接放入无返回,如果队列已满,则会一直阻塞等待;整个过程加锁,会阻塞线程;
//队列满了就开始阻塞等待,知道有空位,然后再执行入队
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();
}
}
2.3、取出元素
a、remove()--对应add,当队列非空时,直接返回首元素且移除首元素,当队列为空时,会抛异常,其本质调用的是poll方法,整个过程会加锁处理,不会阻塞;
public E remove() {
E x = poll();//本质调用的是poll
if (x != null)
return x;
else
throw new NoSuchElementException();
}
b、poll()--对应offer,当队列非空时,直接返回首元素且移除首元素,当队列为空时,会直接返回null,整个过程加锁,但不阻塞;
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (count == 0) ? null : dequeue();//空时直接返回null
} finally {
lock.unlock();
}
}
c、poll(long timeout, TimeUnit unit) --对应offer构造2,当队列非空时,直接返回首元素且移除首元素,当队列为空时,会等待指定时间再试,如果队列还是为空,则返回null,否则返回首元素且移除首元素;
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 dequeue();
} finally {
lock.unlock();
}
}
3、使用示例
import java.util.Date;
import java.util.Scanner;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 数据结构为数组,是有界队列,需要指定容量,支持公平锁和公平锁,操作加锁线程安全
* 常用方法,
* 插入:add、offer、put
* 取出:remove poll take
*
*/
public class ArrayBlockingQueueTest {
private ArrayBlockingQueue<String> blockingQueue = new ArrayBlockingQueue<String>(10, true);
private ExecutorService threadPool = Executors.newSingleThreadExecutor();
public ArrayBlockingQueueTest() {
}
private void log(String msg) {
System.out.println(Thread.currentThread().getName() + "-->>" + msg);
}
private void console() {
threadPool.submit(new Runnable() {
public void run() {
log("请输入指令:");
Scanner sc = new Scanner(System.in);
String readLine = null;
String tmpValue = null;
try {
while (true) {
readLine = sc.nextLine();
tmpValue = readLine + "_" + (new Date()).getTime();
if ("quit".equalsIgnoreCase(readLine)) {
log("bye");
break;
} else if ("add".equalsIgnoreCase(readLine)) {
blockingQueue.add(tmpValue);// 满了会抛异常
log(tmpValue);
} else if ("offer".equalsIgnoreCase(readLine)) {
boolean isOk = blockingQueue.offer(tmpValue);// 满了会返回false
log(tmpValue);
log(isOk + "");
} else if ("put".equalsIgnoreCase(readLine)) {
blockingQueue.put(tmpValue);// 满了会阻塞
log(tmpValue);
} else if ("remove".equalsIgnoreCase(readLine)) {
log(blockingQueue.remove());// 空了会抛异常
} else if ("poll".equalsIgnoreCase(readLine)) {
log(blockingQueue.poll());// 空了会返回null
} else if ("take".equalsIgnoreCase(readLine)) {
log(blockingQueue.take());// 空了会阻塞等待
}
}
} catch (Exception ex) {
log(ex.getMessage());
} finally {
sc.close();
}
}
});
// threadPool.shutdown();
}
public static void main(String[] args) {
ArrayBlockingQueueTest arrayBlockingQueueTest = new ArrayBlockingQueueTest();
arrayBlockingQueueTest.console();
}
}