1.很久没写博客了,原因是重新找了份电商后台工作。今天来简单解析下JDK的ArrayBlockingQueue阻塞循环队列。
首先我们来看下ArrayBlockingQueue的成员变量
/**底层的 队列数组*/
final Object[] items;
/**读取元素时的下标*/
int takeIndex;
/**添加元素时 的 下标*/
int putIndex;
/**队列中元素个数*/
int count;
final ReentrantLock lock;
private final Condition notEmpty;
private final Condition notFull;
构造函数
public ArrayBlockingQueue(int capacity) {
this(capacity, false);
}
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();
}
take(出队)方法
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
/* lockInterruptibly: 尝试获取锁,如果锁正在被其它线程占用,则阻塞, 直到其它线程调用此线程的interrupt()方法,将抛出IterruptException
*/
lock.lockInterruptibly();
try {
/*
如果此时队列中的元素个数为0,那么就让当前线程wait,并且释放锁。注意:这里使用了while进行重复检查,是为了防止当前线程可能由于 其他未知的原因被唤醒。
*/
while (count == 0)
notEmpty.await();
//如果队列不为空,则从队列的头部取元素
return extract();
} finally {
//完成锁的释放
lock.unlock();
}
}
extract方法
private E extract() {
final Object[] items = this.items;
E x = (E) items[takeIndex];//根据takeIndex来获取当前的元素
items[takeIndex] = null;
takeIndex = inc(takeIndex); // takeIndex加1 ,如果takeIndex等于队列最大则置为0
--count; // 队列元素减1
notFull.signal(); // 通知其它 生产者线程
return x;
}
inc方法
final int inc(int i) {
//当takeIndex的值等于数组的长度时,就会重新置为0,这个一个循环递增的过程,这里看出ArrayBlockingQueue其实是一个循环队列
return (++i == items.length) ? 0 : i;
}
put方法
public void put(E e) throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length) // 队列满了
notFull.await(); // 当前线程等待
insert(e);
} finally {
lock.unlock();
}
}
insert方法
private void insert(E x) {
//将当前元素设置到putIndex位置
items[putIndex] = x;
//让putIndex++
putIndex = inc(putIndex);
//将队列的大小加1
++count;
//唤醒其他正在处于等待状态的线程
notEmpty.signal();
}
重点就是这些,就是利用jdk1.5的condition和Lock实现的生产者消费者队列。
老生常谈:深圳有爱好音乐的会打鼓(吉他,键盘,贝斯等)的程序员和其它职业可以一起交流加入我们乐队一起嗨。我的QQ:657455400