源码分析
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();//判断队列不满
}
put(E e)
public void put(E e) throws InterruptedException {
checkNotNull(e);//检查e是不是空
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();//获取可中断的锁
try {
while (count == items.length)//判断数组是不是满了
notFull.await();//condition.await()等待
enqueue(e);//没有满就入队列
} finally {
lock.unlock();//释放锁
}
}
enqueue(E x)
private void enqueue(E x) {
final Object[] items = this.items;
items[putIndex] = x;//入队列尾
if (++putIndex == items.length)//队列尾指针加1,如果等于数组长度,说明队列满了
putIndex = 0;//将队列尾指针变成0,实现一个循环队列
count++;//队列中真正的元素
notEmpty.signal();//队列里有元素说明非空,那么会唤醒等待的线程去去元素
}
take()
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();//获取可中断锁
try {
while (count == 0)//count==0时说明队列里没有元素
notEmpty.await();//线程等待
return dequeue();//否则,出队
} finally {
lock.unlock();//释放锁
}
}
dequeue()
private E dequeue() {
final Object[] items = this.items;
@SuppressWarnings("unchecked")
E x = (E) items[takeIndex];//获取队列头的值
items[takeIndex] = null;//删除队列头
if (++takeIndex == items.length)//队列头指针加1,如果队列到达了队列尾的话,说明队列没有元素了
takeIndex = 0;//头指针赋值为0,实现一个循环队列
count--;//否则真实的元素个数减1
if (itrs != null)
itrs.elementDequeued();
notFull.signal();//队列没有满,通知等待的线程执行入队操作
return x;
}
LinkedBlockingQueue
构造方法
public LinkedBlockingQueue(int capacity) {
if (capacity <= 0) throw new IllegalArgumentException();
this.capacity = capacity;
last = head = new Node<E>(null);//初始化节点
}
put(E e)
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 {
while (count.get() == capacity) {//判断是否满了
notFull.await();//如果满了,等待
}
enqueue(node);//入队
c = count.getAndIncrement();//元素个数原子递增
if (c + 1 < capacity)
notFull.signal();//没有满,告诉等待的线程执行插入操作
} finally {
putLock.unlock();//释放锁
}
if (c == 0)
signalNotEmpty();//队列有元素,让获取元素的线程执行
}
take()
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) {//判断队列是否为空
notEmpty.await();//为空线程等待
}
x = dequeue();//否则出队操作,队列头出队
c = count.getAndDecrement();//原子递减
if (c > 1)
notEmpty.signal();//非空,让获取元素的线程执行
} finally {
takeLock.unlock();//释放锁
}
if (c == capacity)
signalNotFull();//唤醒消费的线程去获取元素
return x;//返回队列头的元素
}
其实这些阻塞队列感觉就类似是操作系统里的生产者和消费者模型,由信号量去协调各个进程之间的通信
阻塞队列其他的方法基本和上边类似,比如offer方法也是向队列中插入元素,只不过不会阻塞。还有poll方法从数组中取元素,没有元素是不阻塞的。