源码剖析之ArrayBlockingQueue

本文深入解析了ArrayBlockingQueue的工作原理及其实现细节,包括其实现的阻塞效果、作为生产者消费者模型工具的优势,以及其内部使用的ReentrantLock锁和Condition条件对象。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ArrayBlockingQueue 是jdk1.5 新提供的阻塞队列,实现了固定大小的队列。

功能:
1、阻塞的效果 。put时如果元素已经满,那么阻塞,get时 如果队列为空,那么阻塞。
2、是实现生产者消费者模型的极好的备选工具。

实现依赖:
[b]1、lock锁(内存的可见性、互斥访问、限制编译器的代码优化调整)
2、Condition条件通知(线程间的协作)[/b]

注意点:代码中多次用的signal 而不是signalAll 有原因的:
1、signalAll 唤醒所有等待的线程,事实上只能有一个通过获得锁,那么会增加锁竞争的几率。效率也低,如果用signal ,那么仅唤醒一个线程,这正是我们所需要的场景!


为了看清楚ArrayBlockingQueue 的工作原理,请参看其源代码的分析如下:

package java.util.concurrent;
import java.util.concurrent.locks.*;
import java.util.*;


public class ArrayBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {


private static final long serialVersionUID = -817911632652898426L;

/** 队列的项,底层是数组,final 修饰意味着 ArrayBlockingQueue 是固定大小的队列 */
private final E[] items;
/** 对数组items 下一个 take, poll or remove 操作的索引index */
private int takeIndex;
/** 对数组items 下一个 put, offer, or add 操作的索引index */
private int putIndex;
/**队列中数据项的数量 ,必须在lock当前锁的情况下才可以使用
注意:count 不需要volitile 修饰, tackIndex putIndex 都一样,因为使用它们的场景都有lock 锁,所以内存可见性和编译代码调整的优化 得到安全的保障!!
*/
private int count;

/*
* Concurrency control uses the classic two-condition algorithm
* found in any textbook.
*/

/** 数据访问的锁*/
private final ReentrantLock lock;
/** 非空等待条件 */
private final Condition notEmpty;
/** 非满等待条件 */
private final Condition notFull;

// Internal helper methods

/**
*数组是循环,如果i == items.length-1 ,那么下一个index =0 从头开始
*/
final int inc(int i) {
return (++i == items.length)? 0 : i;
}

/**
* Inserts element at current put position, advances, and signals.
* Call only when holding lock.
当前的putIndex位置上放置x元素(只能在获取锁的情况下调用)
*/
private void insert(E x) {
items[putIndex] = x;
putIndex = inc(putIndex); //插入数据后,下一个要插入的位置需要 +1
++count; //数量+1
notEmpty.signal(); //含义:一旦插入新数据,那么需要通知notEmpty.wait 条件下等待的线程(take数据的线程)
}

/**
* Extracts element at current take position, advances, and signals.
* 取一个元素 (只能在获取锁的情况下调用)
*/
private E extract() {
final E[] items = this.items;
E x = items[takeIndex];// 获取当前takeIndex的元素
items[takeIndex] = null;
takeIndex = inc(takeIndex); // 调整下一个获取元素的的位置
--count; //数量要减一个
notFull.signal(); //取出后,通知添加数据的线程,items已经不满了。
return x;
}

/**
* 擅长在i位置的item元素(Call only when holding lock.)
*
*/
void removeAt(int i) {
final E[] items = this.items;
// if removing front item, just advance
if (i == takeIndex) { //如果i是下一个将要获取的值,那么这个值直接置空即可!!!
items[takeIndex] = null;
takeIndex = inc(takeIndex); //增加下一个获取值的位置
} else {
// slide over all others up through putIndex.
for (;;) { //否则
int nexti = inc(i);
if (nexti != putIndex) { //next 不等于 下一个要放数据的位置
items[i] = items[nexti]; //此处的逻辑是移动i+1 之后的元素到i位置上
i = nexti;
} else { 如果nexti 为 putIndex
items[i] = null; //i = nexti 那么i位置置空,putIndex = i
putIndex = i;
break;
}
}
}
--count; //数量--
notFull.signal(); //含义:删除数据后,要通知notFull条件 已经非空,释放一个notFull.wait 的线程
}

/**
*
*/
public ArrayBlockingQueue(int capacity) {
this(capacity, false);
}


public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = (E[]) new Object[capacity];
lock = new ReentrantLock(fair); //是否是公平锁
notEmpty = lock.newCondition();//非空的严谨条件
notFull = lock.newCondition(); //非满的条件,
//比如:如果put操作因为空间不足,那么将会一直阻塞(notFull wait),如果这期间没有新数据读取了,那么需要调用:notFull wait方法。
}


public ArrayBlockingQueue(int capacity, boolean fair,
Collection<? extends E> c) {
this(capacity, fair);
if (capacity < c.size())
throw new IllegalArgumentException();

for (Iterator<? extends E> it = c.iterator(); it.hasNext();)
add(it.next());
}

/**
* 添加元素
*/
public boolean add(E e) {
return super.add(e);
}

/**
* 添加元素如已满,那么返回false ,否则返回true
*
* @throws NullPointerException if the specified element is null
*/
public boolean offer(E e) {
if (e == null) throw new NullPointerException();
final ReentrantLock lock = this.lock;
lock.lock(); //变更数据结构的操作,必须枷锁,另外count变量也必须在lock加锁的情况下使用
try {
if (count == items.length) //如没有空间了,那么返回flase
return false;
else {
insert(e);
return true;
}
} finally {
lock.unlock();
}
}

/**
* 在数组的尾部放数据
*/
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
final E[] items = this.items;
final ReentrantLock lock = this.lock;//先加锁
lock.lockInterruptibly();
try {
try {
while (count == items.length) //如果已经满,那么等待
notFull.await();
} catch (InterruptedException ie) {
notFull.signal(); // 如果notFull.await 被打断,其实我认为:此处做这个signal 没有太多意义,做了也是白做,因为items.length 、count没有变啊!!!
throw ie;
}
insert(e);
} finally {
lock.unlock();
}
}

/**
插入数据
*/
public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException {

if (e == null) throw new NullPointerException();
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
for (;;) {
if (count != items.length) { //如果count != length 就是数组不满呗!那么直接插入即可
insert(e);
return true;
}
if (nanos <= 0)
return false;
try {
nanos = notFull.awaitNanos(nanos); //等待nanos纳秒 注意必须这样用!
} catch (InterruptedException ie) {
notFull.signal(); // propagate to non-interrupted thread
throw ie;
}
}
} finally {
lock.unlock();
}
}

public E poll() {
final ReentrantLock lock = this.lock;
lock.lock(); //必须枷锁
try {
if (count == 0) //取数据,如果没有那么返回null
return null;
E x = extract();
return x;
} finally {
lock.unlock();
}
}

public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
try {
while (count == 0) //如果为空,那么notEmpty await 进入等待状态
notEmpty.await();
} catch (InterruptedException ie) {
notEmpty.signal(); // propagate to non-interrupted thread
throw ie;
}
E x = extract();
return x;
} finally {
lock.unlock();
}
}

public E poll(long timeout, TimeUnit unit) throws InterruptedException {
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
for (;;) {
if (count != 0) { //如果还有元素,我以及获得lock锁了,所以count 是不会有竞争的
E x = extract();
return x;
}
if (nanos <= 0)
return null;
try {
nanos = notEmpty.awaitNanos(nanos); //如果没有数据那么 wait nanos的时间
} catch (InterruptedException ie) {
notEmpty.signal(); // 传播异常事必要的。但是notEmpty.signal 是完全没必要的
throw ie;
}

}
} finally {
lock.unlock();
}
}

public E peek() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (count == 0) ? null : items[takeIndex];
} finally {
lock.unlock();
}
}

// this doc comment is overridden to remove the reference to collections
// greater in size than Integer.MAX_VALUE
/*
*/
public int size() {
final ReentrantLock lock = this.lock;
lock.lock();
try { //返回的count 必须有lock锁 保卫,否则数据事安全的。
return count;
} finally {
lock.unlock();
}
}

// 返回还剩下的元素

public int remainingCapacity() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return items.length - count;
} finally {
lock.unlock();
}
}

/**
* Removes a single instance of the specified element from this queue,
删除一个在queue中的元素
*
*/
public boolean remove(Object o) {
if (o == null) return false;
final E[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock(); //删除元素需要加锁
try {
int i = takeIndex; //记录的要取数据的位置
int k = 0; //记录已经取得的元素数量
for (;;) {
if (k++ >= count)//如果已经遍历的元素数量k 超过count ,那么可以认定已经找完,没有找到 o 数据。
return false;
if (o.equals(items[i])) { //如果o == items[i] ,那么删除i位置的元素
removeAt(i);
return true;
}
i = inc(i); //如果没有找到,那么找下一个!!
}

} finally {
lock.unlock();
}
}

public boolean contains(Object o) {
if (o == null) return false;
final E[] items = this.items;
final ReentrantLock lock = this.lock; //为了防止遍历中,有数据结构的变动
lock.lock();
try {
int i = takeIndex;
int k = 0;
while (k++ < count) { //如果还有元素
if (o.equals(items[i])) //找到一个可以和在以前的人,那么可以直接返回
return true;
i = inc(i);
}
return false;
} finally {
lock.unlock();
}
}


public Object[] toArray() {
final E[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] a = new Object[count];
int k = 0;
int i = takeIndex;
while (k < count) {
a[k++] = items[i];
i = inc(i);
}
return a;
} finally {
lock.unlock();
}
}

public <T> T[] toArray(T[] a) {
final E[] items = this.items;
final ReentrantLock lock = this.lock; //复制需要加锁!
lock.lock();
try {
if (a.length < count)
a = (T[])java.lang.reflect.Array.newInstance( //生成数组实例的方法!!
a.getClass().getComponentType(), //数组的
count //数量
);

int k = 0;
int i = takeIndex; //取元素的职位,tckeIndex不变的,不能变的!!
while (k < count) { //如果k<count 那么说明还有数据!!
a[k++] = (T)items[i];
i = inc(i);
}
if (a.length > count)
a[count] = null; //做一个特殊处理,不处理也可以的!
return a;
} finally {
lock.unlock();
}
}

public String toString() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return super.toString();
} finally {
lock.unlock();
}
}

/**
* 情况缓冲
*/
public void clear() {
final E[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock();
try {
int i = takeIndex; //取元素的位置
int k = count; //总元素的数量
while (k-- > 0) {
items[i] = null;
i = inc(i); //让下一个元素的位置+1
}
count = 0;
putIndex = 0;
takeIndex = 0;
notFull.signalAll(); //非满的条件通知
} finally {
lock.unlock();
}
}

/**
* 把队列中的item放到c 容器中
*/
public int drainTo(Collection<? super E> c) {
if (c == null)
throw new NullPointerException();
if (c == this)
throw new IllegalArgumentException();
final E[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock(); //先获得锁
try {
int i = takeIndex;
int n = 0;
int max = count; //指定最大count
while (n < max) {
c.add(items[i]);
items[i] = null;
i = inc(i);
++n;
}
if (n > 0) { //如果n >0 ,其实就是说count >0,那么把相关值重置
count = 0;
putIndex = 0;
takeIndex = 0;
notFull.signalAll(); //此处的signalAll 是必须的,而不能是signal !,他要通知到所有的处于put等待状态的线程!!!
}
return n;
} finally {
lock.unlock();
}
}

/**
* 把队列中的item放到c 容器中
*/
public int drainTo(Collection<? super E> c, int maxElements) {
if (c == null)
throw new NullPointerException();
if (c == this)
throw new IllegalArgumentException();
if (maxElements <= 0)
return 0;
final E[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock();
try {
int i = takeIndex;
int n = 0;
int sz = count;
int max = (maxElements < count)? maxElements : count;
while (n < max) { /
c.add(items[i]);
items[i] = null;
i = inc(i);
++n;
}
if (n > 0) {
count -= n;
takeIndex = i;
notFull.signalAll();
}
return n;
} finally {
lock.unlock();
}
}


/**
* 生成一个迭代器
*
* @return an iterator over the elements in this queue in proper sequence
*/
public Iterator<E> iterator() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return new Itr(); // 必须枷锁的情况下完成
} finally {
lock.unlock();
}
}

/**
* Iterator for ArrayBlockingQueue
*/
private class Itr implements Iterator<E> {
/**
* 下一个返回的元素的index值
*/
private int nextIndex;

/**
* 下一个元素
*/
private E nextItem;

/**
* 返回上一次返回的记录的位置,如果上一个操作是删除操作,那么lastRet值为-1
*/
private int lastRet;

Itr() {
lastRet = -1; //初始化为-1
if (count == 0)
nextIndex = -1; //如果没有元素,那么nextIndex也置为-1
else { //否则赋相应的值
nextIndex = takeIndex;
nextItem = items[takeIndex];
}
}

public boolean hasNext() {
/*
* No sync. We can return true by mistake here
* only if this iterator passed across threads,
* which we don't support anyway.

注意:此方法事不同步的!! 在多线程环境下 可能错误的返回true,nextIndex 只能标志:读取下一个元素从哪儿开始。 jdk不对同步做支持,其事实上即便支持也没什么实际意义!!! */
return nextIndex >= 0;
}

/**
* 如果 nextIndex 是有效的,那么设置nextItem值
*/
private void checkNext() {
if (nextIndex == putIndex) { //已经put的位置了,已经没有数据可取
nextIndex = -1;
nextItem = null;
} else {
nextItem = items[nextIndex];
if (nextItem == null)
nextIndex = -1;
}
}

/* [b]获取下一个元素: 其实此方法我感觉几乎没什么意义! 不准确,还可能抛异常,还不如toArray 得了[/b]*/
public E next() {
final ReentrantLock lock = ArrayBlockingQueue.this.lock;
lock.lock();
try {
if (nextIndex < 0)
throw new NoSuchElementException();
lastRet = nextIndex;
E x = nextItem;
nextIndex = inc(nextIndex);
checkNext();
return x;
} finally {
lock.unlock();
}
}

/** 同上*/
public void remove() {
final ReentrantLock lock = ArrayBlockingQueue.this.lock;
lock.lock();
try {
int i = lastRet;
if (i == -1)
throw new IllegalStateException();
lastRet = -1;

int ti = takeIndex;
removeAt(i);
// back up cursor (reset to front if was first element)
nextIndex = (i == ti) ? takeIndex : i;
checkNext();
} finally {
lock.unlock();
}
}
}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值