先上一张Java集合的框架图,便于参考
以下所有特性仅代表自JAVA 1.8
Queue
/*
* @since 1.5
*/
public interface Queue<E> extends Collection<E> {
//在不违反容量限制的情况下,添加一个元素到队列中,如果队列容量不足则抛出异常
boolean add(E e);
//在不违反容量限制的情况下,添加一个元素到队列中,如果队列容量不足,通常使用此方法,此时此方法优于add()
boolean offer(E e);
//取出并移除队列头部元素,如果队列为空则抛出异常
E remove();
//取出并移除队列头部元素,如果队列为空则返回NULL
E poll();
//取出队列头部元素,但不会移除,如果队列为空则抛出异常
E element();
//取出队列头部元素,但不会移除, 如果队列为空则返回NULL
E peek();
}
BlockingQueue
public interface BlockingQueue<E> extends Queue<E> {
boolean add(E e);
boolean offer(E e);
//添加元素到队列中,如果队列容量不足,则等待
void put(E e) throws InterruptedException;
//添加元素到队列中,如果队列容量不足,则等待特定的一段时间
boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException;
//取出并移除队列的头部元素,如果队列为空则等待,直到队列有新的元素加入
E take() throws InterruptedException;
//取出并移除队列的头部元素,如果队列为空则等待特定的一段时间
E poll(long timeout, TimeUnit unit) throws InterruptedException;
//返回队列的剩余空间
int remainingCapacity();
//移除在队列中给定的元素,如果队列中存在多个给定的元素,则移除首个相同的元素
boolean remove(Object o);
//返回当前队列是否包含给定的对象
public boolean contains(Object o);
//将队列中的元素移除,并添加到给定的集合中
int drainTo(Collection<? super E> c);
//移除给定数量的元素,并且将元素添加到给定的集合中
int drainTo(Collection<? super E> c, int maxElements);
}
Throw Exception | Special Value | Blocks | Times out | |
---|---|---|---|---|
Insert | add(e) | offeer(e) | put(e) | offer(e,time,unit) |
Remove | remove() | poll() | take() | poll(time,unit) |
Examine | element() | peek() |
非阻塞队列
线程不安全的
PriorityQueue
PriorityQueue(优先队列)。优先队列的作用是能保证每次取出的元素都是队列中权值最小的(Java的优先队列每次取最小元素,C++的优先队列每次取最大元素
public class PriorityQueue<E> extends AbstractQueue<E> implements java.io.Serializable{
private static final int DEFAULT_INITIAL_CAPACITY = 11; //默认初始容量11
transient Object[] queue; //使用Object数组实现
public PriorityQueue(int initialCapacity) {
this(initialCapacity, null);
}
//队列扩容
private void grow(int minCapacity) {
int oldCapacity = queue.length;
// Double size if small; else grow by 50%
int newCapacity = oldCapacity + ((oldCapacity < 64) ?
(oldCapacity + 2) :
(oldCapacity >> 1));
// overflow-conscious code
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
queue = Arrays.copyOf(queue, newCapacity);
}
}
PriorityQueue实现了Queue接口,不允许放入null元素;其通过堆实现,具体说是通过完全二叉树(complete binary tree)实现的小顶堆(任意一个非叶子节点的权值,都不大于其左右子节点的权值----此处权值即为每个叶子节点上的数值),也就意味着可以通过数组来作为PriorityQueue的底层实现
LinkedList
使用双向链表结构实现, Java List参考.
阻塞队列
线程安全的
ArrayBlockingQueue
- AQS(AbstractQueuedSynchronizer)实现 AQS是JDK下提供的一套用于实现基于FIFO等待队列的阻塞锁和相关的同步器的一个同步框架。这个抽象类被设计为作为一些可用原子int值来表示状态的同步器的基类
- 使用数组(Object[])实现的阻塞队列,必须在创建ArrayBlockingQueue的时候指定队列大小,并且默认使用非公平锁 ,FIFO队列
缺点:由于put和take都使用同一把锁,因此效率不高
//since 1.5
public class ArrayBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, java.io.Serializable {
//使用Object数组
final Object[] items;
int takeIndex;
int putIndex;
int count;
final ReentrantLock lock;
private final Condition notEmpty;
private final Condition notFull;
//初始化必须指定队列大小,默认使用非公平锁
public ArrayBlockingQueue(int capacity) {
this(capacity, false);
}
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
- AQS(AbstractQueuedSynchronizer)实现 AQS是JDK下提供的一套用于实现基于FIFO等待队列的阻塞锁和相关的同步器的一个同步框架。这个抽象类被设计为作为一些可用原子int值来表示状态的同步器的基类
- 使用链表(Node)结构实现的阻塞队列,如果在创建LinkedBlockingQueue的时候不指定队列大小,则使用默认的最大容量MAX_VALUE(2^31 -1)FIFO队列
优势:使用了put和take两把锁,对于不同场景使用不同的锁,效率更高
public class LinkedBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, java.io.Serializable {
transient Node<E> head;
private transient Node<E> last;
private final ReentrantLock takeLock = new ReentrantLock(); //ReentrantLock就是基于AQS()实现的
private final ReentrantLock putLock = new ReentrantLock();
private final Condition notEmpty = takeLock.newCondition();
private final Condition notFull = putLock.newCondition();
static class Node<E> {
E item;
Node<E> next;
}
public LinkedBlockingQueue() {
this(Integer.MAX_VALUE);
}
public LinkedBlockingQueue(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
last = head = new Node<E>(null);
}
}
SynchronizeQueue
- CAS(Compare And Swap)实现 sun.misc.Unsafe 类提供了硬件级别的原子操作来实现这个CAS
//@since 1.5
public class SynchronousQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, java.io.Serializable {
abstract static class Transferer<E> {
abstract E transfer(E e, boolean timed, long nanos);
}
//非公平模式下使用
static final class TransferStack<E> extends Transferer<E> {
static final class SNode {
volatile SNode next; // next node in stack
volatile SNode match; // the node matched to this
volatile Thread waiter; // to control park/unpark
Object item; // data; or null for REQUESTs
int mode;
volatile SNode head;
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe(); //基于CAS实现
Class<?> k = SNode.class;
matchOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("match"));
nextOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("next"));
} catch (Exception e) {
throw new Error(e);
}
}
boolean tryMatch(SNode s) {
if (match == null &&
UNSAFE.compareAndSwapObject(this, matchOffset, null, s)) { // Compare and Swap
Thread w = waiter;
if (w != null) { // waiters need at most one unpark
waiter = null;
LockSupport.unpark(w);
}
return true;
}
return match == s;
}
}
}
//公平模式下使用
static final class TransferQueue<E> extends Transferer<E> {
transient volatile QNode head;
transient volatile QNode tail;
transient volatile QNode cleanMe;
static final class QNode {
volatile QNode next; // next node in queue
volatile Object item; // CAS'ed to or from null
volatile Thread waiter; // to control park/unpark
final boolean isData;
private static final sun.misc.Unsafe UNSAFE;
private static final long itemOffset;
private static final long nextOffset;
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class<?> k = QNode.class;
itemOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("item"));
nextOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("next"));
} catch (Exception e) {
throw new Error(e);
}
}
}
}
}
PriorityBlockingQueue
PriorityBlockingQueue 队列内部使用二叉树堆维护元素优先级,内部使用数组作为元素存储的数据结构,这个数组是可以扩容的,当前元素个数 >= 最大容量的时候会通过算法扩容,
出队的时候始终保证出队的元素是堆树的根节点,而不是在队列里面停留时间最长的元素,默认元素优先级比较规则是使用元素的compareTo方法来做,用户可以自定义优先级的比较优先级。
DelayQueue
延迟队列,存储的对象只能在设置时间到期时才能从队列中取走。
public class DelayQueue<E extends Delayed> extends AbstractQueue<E> implements BlockingQueue<E> {
private final transient ReentrantLock lock = new ReentrantLock();
//Delayed是一个具有过期时间的元素
//用于根据delay时间排序的优先级队列
private final PriorityQueue<E> q = new PriorityQueue<E>();
//用于优化阻塞通知的线程元素leader
private Thread leader = null;
//用于实现阻塞和通知的Condition对象
private final Condition available = lock.newCondition();
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
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();
}
}
}
DelayQueue能做什么
- 淘宝订单业务:下单之后如果三十分钟之内没有付款就自动取消订单。
- 饿了吗订餐通知:下单成功后60s之后给用户发送短信通知。
- 关闭空闲连接。服务器中,有很多客户端的连接,空闲一段时间之后需要关闭之。
- 缓存。缓存中的对象,超过了空闲时间,需要从缓存中移出。
- 任务超时处理。在网络协议滑动窗口请求应答式交互时,处理超时未响应的请求等