概述
- BlockingQueue是阻塞队列。
- BlockingQueue继承自Queue,在Queue的基础上添加了阻塞方法put()和take(),
- BlockingQueue是接口,由实现类实现相应的阻塞方法。例如:ArrayBlockingQueue,SychronousQueue,TranferQueue,LinkedBlockingQueue,PriorityBlockingQueue等等。
ArrayBlockingQueue
底层是通过数组作为容器存储,使用的是reentrantLock进行加锁,使用不同的condition进行不同操作
//数组用于存储数据
final Object[] items;
/** 用于put操作的condition */
private final Condition notFull;
/** 用于take操作的condition */
private final Condition notEmpty;
public void put(E e) throws InterruptedException {
//判断非空
checkNotNull(e);
final ReentrantLock lock = this.lock;
//加锁可被打断
lock.lockInterruptibly();
try {
//当数据到达上限时,将put的condition等待
while (count == items.length)
notFull.await();
enqueue(e);//添加到数组容器中
} finally {
lock.unlock();//释放锁
}
}
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();//可打断锁
try {
while (count == 0) //如果数据为空,就让take的condition等待
notEmpty.await();
return dequeue();
} finally {
lock.unlock();
}
}
LinkedBlockingQueue
底层是用链表存储,take获取的是head.next ,put插入的是末尾,可以进行读写分离
读写锁分离
private final ReentrantLock takeLock = new ReentrantLock();
private final Condition notEmpty = takeLock.newCondition();
private final ReentrantLock putLock = new ReentrantLock();
private final Condition notFull = putLock.newCondition();
public void put(E e) throws InterruptedException {
//非空判断 if (e == null) throw new NullPointerException();
int c = -1;
//新增节点
Node<E> node = new Node<E>(e);
final ReentrantLock putLock = this.putLock;//写锁
final AtomicInteger count = this.count;
//加锁
putLock.lockInterruptibly();
try {
//如果到达上限就让put的condition 等待
while (count.get() == capacity) {
notFull.await();
}
enqueue(node);//添加数据
c = count.getAndIncrement();
if (c + 1 < capacity) //如果数据添加后没有到达上限,唤醒notFull
notFull.signal();
} finally {
putLock.unlock();
}
if (c == 0) //当有一条数据插入是,就可以将notEmpty唤醒了
signalNotEmpty();
}
public E take() throws InterruptedException {
E x;
int c = -1;
final AtomicInteger count = this.count;
final ReentrantLock takeLock = this.takeLock;//读锁
takeLock.lockInterruptibly();//上锁
try {
while (count.get() == 0) {//数据为空时,takecondition等待
notEmpty.await();
}
x = dequeue();
c = count.getAndDecrement();
if (c > 1)
notEmpty.signal();
} finally {
takeLock.unlock();
}
if (c == capacity)
signalNotFull();
return x;
}
PriorityBlockingQueue
优先级缓存队列,默认是小根堆,可以添加比较器来自定义
//三种构造方式 ,无参,设置默认长度,比价器
public PriorityBlockingQueue() {
this(DEFAULT_INITIAL_CAPACITY, null);
}
public PriorityBlockingQueue(int initialCapacity) {
this(initialCapacity, null);
}
public PriorityBlockingQueue(int initialCapacity,
Comparator<? super E> comparator) {
if (initialCapacity < 1)
throw new IllegalArgumentException();
this.lock = new ReentrantLock();
this.notEmpty = lock.newCondition();
this.comparator = comparator;
this.queue = new Object[initialCapacity];
}
PUT方法 因为是数组存储,先判断是否需要扩容,默认每次扩大为原来的1.5倍, 如果没设置比较器就用默认的(小根堆),有设置就用自定义的比较器
public void put(E e) {
offer(e);
}
public boolean offer(E e) {
if (e == null)
throw new NullPointerException();
final ReentrantLock lock = this.lock;
lock.lock();
int n, cap;
Object[] array;
while ((n = size) >= (cap = (array = queue).length))
tryGrow(array, cap);//扩容
try {
Comparator<? super E> cmp = comparator;
if (cmp == null)
siftUpComparable(n, e, array); //使用默认比较器
else
siftUpUsingComparator(n, e, array, cmp); //自定义比较器
size = n + 1;
notEmpty.signal();
} finally {
lock.unlock();
}
return true;
}
take方法
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
E result;
try {
while ( (result = dequeue()) == null)
notEmpty.await();
} finally {
lock.unlock();
}
return result;
}
/**
* 怎么存,怎么取,使用相同的比较器去移除数据
*/
private E dequeue() {
int n = size - 1;
if (n < 0)
return null;
else {
Object[] array = queue;
E result = (E) array[0];
E x = (E) array[n];
array[n] = null;
Comparator<? super E> cmp = comparator;
if (cmp == null)
siftDownComparable(0, x, array, n);
else
siftDownUsingComparator(0, x, array, n, cmp);
size = n;
return result;
}
}