下图是BlockingQueue接口的主要实现
我们先看第一个ArrayBlockingQueue
主要属性
/** 存放队列元素的数组 */ final Object[] items; /** 出队列的当前索引值 */ int takeIndex; /** 入队列的下一个索引值 */ int putIndex; /** 队列大小 */ int count; /** 队列操作锁 */ final ReentrantLock lock; /** 出队列Condition */ private final Condition notEmpty; /** 入队列Condition */ private final Condition notFull; /** * 队列活动共享状态 * */ transient Itrs itrs = null;
下面我们看两个主要方法
public void put(E e) throws InterruptedException {
checkNotNull(e);//判空
final ReentrantLock lock = this.lock;//创建锁
lock.lockInterruptibly();//可中断获取锁
try {
while (count == items.length)
notFull.await();//队列已满,释放锁
enqueue(e);//入队列
} finally {
lock.unlock();//释放锁
}
}
这里重点分析下aqs中Condition的应用
public E take() throws InterruptedException { final ReentrantLock lock = this.lock; lock.lockInterruptibly();//可中断获取锁 try { while (count == 0) notEmpty.await();//非空等待 return dequeue();//出队列 } finally { lock.unlock();//释放锁 } }
上面看到在队列已满或者队列为空,分别对应notFull,
notEmpty等待,并且加入了等待队列,那么从哪里唤醒的呢
private void enqueue(E x) { final Object[] items = this.items;//获取元素的数组 items[putIndex] = x;//新元素加入数组 if (++putIndex == items.length) putIndex = 0; count++;//大小加1 notEmpty.signal();//唤醒因队列为空阻塞的线程 }
dequeue()方法类似,不再啰嗦。
private E dequeue() { final Object[] items = this.items; @SuppressWarnings("unchecked") E x = (E) items[takeIndex];//获取出队列元素 items[takeIndex] = null;//置空 if (++takeIndex == items.length)//已经取到最后一个,归零 takeIndex = 0; count--;//大小减1 if (itrs != null) itrs.elementDequeued();//归零,清除弱引用 notFull.signal();//唤醒因队列满等待的线程 return x; }
这里就是为什么使用的await(),signal()方法,而不是使用wait和notify,notifyAll呢,留给大家解答吧。