前言
java.util.concurrent.BlockingQueue:顾名思义,它是一个并发操作队列数据线程安全(JUC)的阻塞队列。阻塞出现在多个场景下,如队列满了则插入阻塞,如果队列空了则提取阻塞,也有可能插入队列操作执行时提取操作阻塞,各个子类的实现不一样。
1 BlockingQueue概览
public interface BlockingQueue<E> extends Queue<E> {
//看注释是添加元素到队列中,成功返回true,如果失败了,则抛出异常?可是接口没定义呀?
//查看多个子类发现都没有实现该方法,这是什么情况?
//查看抽象类AbstractQueue,发现实现在这:
//if (offer(e)) return true; else throw new IllegalStateException("Queue full");
boolean add(E e);
//添加元素到队列中,成功返回true,失败返回false
boolean offer(E e);
//添加元素到队列中,如果没有可用空间则阻塞等待
void put(E e) throws InterruptedException;
//给定时间内进行添加元素操作,成功返回true,超时失败返回false
boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException;
//提取元素并从队列移除,如果操作失败则等待,直到该操作成功
E take() throws InterruptedException;
//提取元素并从队列移除,如果操作失败则等待一定时间,超时后返回null
E poll(long timeout, TimeUnit unit)
throws InterruptedException;
//获取队列空闲容量
int remainingCapacity();
//从队列中移除所有与传参对象‘equals’的对象
boolean remove(Object o);
//判断队列中是否包含与传参对象‘equals’的对象
public boolean contains(Object o);
//将队列中值移除,并剪切到传参集合中
int drainTo(Collection<? super E> c);
//将队列中指定数量(maxElements)的值移除,并剪切到传参集合中
int drainTo(Collection<? super E> c, int maxElements);
}
IDEA类图展示:四个常见阻塞队列(红框)+一个非阻塞队列ConcurrentLinkedQueue(蓝框)
2 四小强介绍(Array,Linked,Sync,Delay)
-
ArrayBlockingQueue:一个用数组实现的有界阻塞队列,直接看代码
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();
}
-
LinkedBlockingQueue:一个由链表结构组成的无界队列,无界指默认可以不设置容量,即容量为Integer.MAX_VALUE,上代码
//链表结构
static class Node<E> {
E item;
Node<E> next;
Node(E x) { item = x; }
}
//首尾节点
transient Node<E> head;
private transient Node<E> last;
//读写锁分离
/** Lock held by take, poll, etc */
private final ReentrantLock takeLock = new ReentrantLock();
/** Wait queue for waiting takes */
private final Condition notEmpty = takeLock.newCondition();
/** Lock held by put, offer, etc */
private final ReentrantLock putLock = new ReentrantLock();
/** Wait queue for waiting puts */
private final Condition notFull = putLock.newCondition();
-
SynchronousQueue:一个不存储元素的阻塞队列,每一次put数据必须等待take数据,反之也是如此。相当于取消了中介,生产者直接将数据传递给消费者,这在多任务并发消费时,具有非常不错的性能。那么队列核心所需要管理的就不是数据,而是生产线程和消费线程,管理方式包含公平模式(FIFO队列)和非公平模式(LIFO栈,默认)。它常用于线程池的缓存队列。
/**
* Creates a {@code SynchronousQueue} with nonfair access policy.
*/
public SynchronousQueue() {
this(false);
}
/**
* Creates a {@code SynchronousQueue} with the specified fairness policy.
*
* @param fair if true, waiting threads contend in FIFO order for
* access; otherwise the order is unspecified.
*/
public SynchronousQueue(boolean fair) {
transferer = fair ? new TransferQueue<E>() : new TransferStack<E>();
}
-
DelayQueue:一个实现延迟获取的无界队列,在创建元素时,可以指定多久才能从队列中获取当前元素。只有延时期满后才能从队列中获取元素。常见应用常见:各类缓存池、定时任务等;
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
for (;;) {
E first = q.peek();
//队列头部为空,则等待
if (first == null)
available.await();
else {
long delay = first.getDelay(NANOSECONDS);
//如果数据到期了则返回当前数据
if (delay <= 0)
return q.poll();
first = null; // don't retain ref while waiting
//如果leader线程非空,则继续等待available条件
if (leader != null)
available.await();
else {
Thread thisThread = Thread.currentThread();
leader = thisThread;
try {
//等待剩余时间
available.awaitNanos(delay);
} finally {
if (leader == thisThread)
leader = null;//重新置空
}
}
}
}
} finally {
if (leader == null && q.peek() != null)
available.signal();//唤醒
lock.unlock();
}
}
3 并发非阻塞队列-ConcurrentLinkedQueue
一个适用于高并发场景下的队列,通过无锁(CAS实现线程安全)的方式,保证了高并发状态下的高性能。看看添加代码:
public boolean offer(E e) {
checkNotNull(e);
final Node<E> newNode = new Node<E>(e);
for (Node<E> t = tail, p = t;;) {
Node<E> q = p.next;
if (q == null) {
// p is last node
if (p.casNext(null, newNode)) {
// Successful CAS is the linearization point
// for e to become an element of this queue,
// and for newNode to become "live".
if (p != t) // hop two nodes at a time
casTail(t, newNode); // Failure is OK.
return true;
}
// Lost CAS race to another thread; re-read next
}
else if (p == q)
// We have fallen off list. If tail is unchanged, it
// will also be off-list, in which case we need to
// jump to head, from which all live nodes are always
// reachable. Else the new tail is a better bet.
p = (t != (t = tail)) ? t : head;
else
// Check for tail updates after two hops.
p = (p != t && t != (t = tail)) ? t : q;
}
}
//通过cas向队列末尾添加元素
private boolean casTail(Node<E> cmp, Node<E> val) {
return UNSAFE.compareAndSwapObject(this, tailOffset, cmp, val);
}
爱家人,爱生活,爱设计,爱编程,拥抱精彩人生!