并发容器中的各种队列 ArrayBlockingQueue**源码剖析
并发容器中的各种队列
ArrayBlockingQueue:数组阻塞队列
LinkendBlockingQueue: 链表阻塞队列
LinkedBlockingDeque: 链表阻塞双端队列
LinkedTransferQueue: 链表阻塞传输队列
SynchronousQueue: 没有缓冲的阻塞队列
PriorityQueue: 带有优先级的⽆界优先级队列
PriorityBlockingQueue:带有优先级数组阻塞队列
DelayQueue: 延迟阻塞队列
ConcurrentLinkedQueue: 基于链表的⽆界线程安全的队列
ArrayBlockingQueue源码剖析
测试案例:模拟生产者生产的速度比较快,消费者消费的速度比较慢,使用ArrayBlockingQueue在中间做一个缓存。
public class ArrayBlockingQueueDemo {
ArrayBlockingQueue queue = new ArrayBlockingQueue(3);
volatile boolean isStop = false;
public static void main(String[] args) {
ArrayBlockingQueueDemo demo = new ArrayBlockingQueueDemo();
demo.test();
}
private void test() {
List<Thread> producerThreadList = new ArrayList<>();
List<Thread> consumerThreadList = new ArrayList<>();
for (int j = 0; j < 3; j++) {
producerThreadList.add((new Thread(this::producer, "包子生产商_" + j)));
}
for (int j = 0; j < 2; j++) {
consumerThreadList.add((new Thread(this::consumer, "消息者_" + j)));
}
producerThreadList.forEach(Thread::start);
consumerThreadList.forEach(Thread::start);
producerThreadList.forEach(this::threadJoin);
isStop = true;
}
private void producer() {
try {
for (int j = 0; j < 4; j++) {
System.out.println(Thread.currentThread().getName() + ", 生产包子_" + j);
queue.put("包子_" + j);
Thread.sleep(200);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void consumer() {
try {
while (!isStop) {
System.err.println(Thread.currentThread().getName() + ", 买到包子:" + queue.take());
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void threadJoin(Thread thread) {
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
运行结果:
包子生产商_0, 生产包子_0
包子生产商_2, 生产包子_0
包子生产商_1, 生产包子_0
消息者_0, 买到包子:包子_0
消息者_1, 买到包子:包子_0
包子生产商_0, 生产包子_1
包子生产商_1, 生产包子_1
包子生产商_2, 生产包子_1
包子生产商_0, 生产包子_2
包子生产商_1, 生产包子_2
消息者_0, 买到包子:包子_0
消息者_1, 买到包子:包子_1
包子生产商_2, 生产包子_2
包子生产商_0, 生产包子_3
消息者_0, 买到包子:包子_1
消息者_1, 买到包子:包子_1
包子生产商_1, 生产包子_3
包子生产商_2, 生产包子_3
消息者_0, 买到包子:包子_2
消息者_1, 买到包子:包子_2
消息者_0, 买到包子:包子_2
消息者_1, 买到包子:包子_3
⼊队⽅法
add(E e): 添加成功返回true,失败抛IllegalStateException异常
offer(E e): 成功返回 true,如果此队列已满,则返回 false。
put(E e): 将元素插⼊此队列的尾部,如果该队列已满,则⼀直阻塞
出队⽅法
remove(Object o): 移除指定元素,成功返回true,失败返回false
poll(): 获取并移除此队列的头元素,若队列为空,则返回 null
take(): 获取并移除此队列的头元素,若队列为空,则⼀直阻塞
检查⽅法
peek(): 获取但不移除此队列的头元素,没有元素则抛
NoSuchElementException异常
element(): 获取但不移除此队列的头;若队列为空,则返回 null。
常用方法分析:
入队:
// 非阻塞
public boolean offer(E e) {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count == items.length)
return false;
else {
enqueue(e);
return true;
}
} finally {
lock.unlock();
}
}
private void enqueue(E x) {
// assert lock.getHoldCount() == 1;
// assert items[putIndex] == null;
final Object[] items = this.items;
items[putIndex] = x;
if (++putIndex == items.length)
putIndex = 0;
count++;
notEmpty.signal(); // 使用notEmpty条件队列唤醒。
}
// 阻塞添加
public void put(E e) throws InterruptedException {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length) // 如果数组已满
notFull.await(); // 使用notFull条件队列阻塞等待
enqueue(e);
} finally {
lock.unlock();
}
}
// 带有超时间的阻塞
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; // 如果已经到了超时间,还是没有添加成功,直接return false。
nanos = notFull.awaitNanos(nanos); //使用notFull条件队列阻塞挂起
}
enqueue(e);
return true;
} finally {
lock.unlock();
}
}
出队:
public boolean remove(Object o) {
if (o == null) return false;
final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count > 0) {
final int putIndex = this.putIndex;
int i = takeIndex;
do {
if (o.equals(items[i])) {
removeAt(i);
return true;
}
if (++i == items.length)
i = 0;
} while (i != putIndex);
}
return false;
} finally {
lock.unlock();
}
}
void removeAt(final int removeIndex) {
// assert lock.getHoldCount() == 1;
// assert items[removeIndex] != null;
// assert removeIndex >= 0 && removeIndex < items.length;
final Object[] items = this.items;
if (removeIndex == takeIndex) {
// removing front item; just advance
items[takeIndex] = null;
if (++takeIndex == items.length)
takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
} else {
// an "interior" remove
// slide over all others up through putIndex.
final int putIndex = this.putIndex;
for (int i = removeIndex;;) {
int next = i + 1;
if (next == items.length)
next = 0;
if (next != putIndex) {
items[i] = items[next];
i = next;
} else {
items[i] = null;
this.putIndex = i;
break;
}
}
count--;
if (itrs != null)
itrs.removedAt(removeIndex);
}
notFull.signal();// 唤醒condition条件队列,又可以往里面放元素了,和上面put方法的notFull.await();相对应
}
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (count == 0) ? null : dequeue();
} finally {
lock.unlock();
}
}
private E dequeue() {
// assert lock.getHoldCount() == 1;
// assert items[takeIndex] != null;
final Object[] items = this.items;
@SuppressWarnings("unchecked")
E x = (E) items[takeIndex];
items[takeIndex] = null;
if (++takeIndex == items.length)
takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
notFull.signal();//
return x;
}
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
notEmpty.await();//
return dequeue();
} finally {
lock.unlock();
}
}
未完待续。。。