前言
ArrayBlockingQueue这个是数组阻塞队列,是BlockingQueue接口的一个实现类,它是一个容量有限的队列,一旦队列大小确认了就不能再改变了,使用方法,下面介绍。
使用
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class Main1 {
public static void main(String[] args) {
// 准备好数组阻塞队列
BlockingQueue<Integer> bq = new ArrayBlockingQueue<Integer>(1024);
// 两个Runnable实现类
Producer producer = new Producer(bq);
Consumer consumer = new Consumer(bq);
Thread t1 = new Thread(producer);
Thread t2 = new Thread(consumer);
// 线程开启
t1.start();
t2.start();
}
}
class Producer implements Runnable {
private BlockingQueue<Integer> blockingQueue = null;
public Producer() {
}
public Producer(BlockingQueue<Integer> blockingQueue) {
this.blockingQueue = blockingQueue;
}
@Override
public void run() {
// try catch主要是put(null),会抛出Exception
try {
// 为了实现一个生产慢,消费快,消费阻塞的效果
Thread.sleep(1000);
blockingQueue.put(1);
Thread.sleep(1000);
blockingQueue.put(4);
Thread.sleep(1000);
blockingQueue.put(555);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class Consumer implements Runnable {
private BlockingQueue<Integer> blockingQueue = null;
public Consumer() {
}
public Consumer(BlockingQueue<Integer> blockingQueue) {
this.blockingQueue = blockingQueue;
}
@Override
public void run() {
try {
System.out.println(blockingQueue.take());
System.out.println(blockingQueue.take());
System.out.println(blockingQueue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
源码解析
其实这个ArrayBlockingQueue的源码并不难,底层就是一个数组在进行操作,我们通过上面的那个Demo代码,进行debug,然后来探究一下到底底层是如何操作的。
// 实例化就不多说了
/**
* Creates an {@code ArrayBlockingQueue} with the given (fixed)
* capacity and default access policy.
*
* @param capacity the capacity of this queue 队列的容量
* @throws IllegalArgumentException if {@code capacity < 1}
*/
public ArrayBlockingQueue(int capacity) {
this(capacity, false);
}
public ArrayBlockingQueue(int capacity, boolean fair) {
// 判断传进来设置的队列容量是不是正整数
if (capacity <= 0)
// 不是肯定要抛出异常,你玩儿我?
throw new IllegalArgumentException();
// final Object[] items; 这个items就是个Object类型的数组
this.items = new Object[capacity];
// 这个锁肯定是要用的,用的是ReentrantLock
lock = new ReentrantLock(fair);
// 两个监视器用于队列满和队列用阻塞之时使用。
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
// 当生产者调用put方法时
public void put(E e) throws InterruptedException {
// 查看放进队列的对象是不是null,是则抛出NPE
checkNotNull(e);
// 拿到前面初始化时候的那把锁
final ReentrantLock lock = this.lock;
// 加锁,其他线程没法用下面的方法了
lock.lockInterruptibly();
try {
// 看看这个队列里面有多少个数,是不是比容量大了
while (count == items.length)
// 队列满了,就等待
notFull.await();
// 没满就入列
enqueue(e);
} 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();
}
// take操作
public E take() throws InterruptedException {
// 拿锁
final ReentrantLock lock = this.lock;
// 加锁
lock.lockInterruptibly();
try {
// 如果队列里面没东西
while (count == 0)
// 阻塞
notEmpty.await();
// 有东西,就返回一个对象
return 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;
}
后记
所以,其实我们后面大部分业务场景用的就是用这个数组阻塞队列,不过,既然是学习的话,当然是其他实现类也是要看看了。