类结构
- final Object[] items; // 队列元素
- int takeIndex; // 出队索引
- int putIndex; // 入队索引
- int count; // 元素数量,注意并不是volatile或原子类
- ReentrantLock lock; // 独占锁
- Condition notEmpty; // 出队锁
- Condition notFull; // 入队锁
从这些属性我们大概就能知道以下:
- 入队和出队用的同一把锁,也就是同一时刻只有一个线程能获取
- 使用数组实现队列,也就不再使用内部Node类了,这会一定程度节省空间
方法
只要是队列还是那些方法offer、poll、peek等,而和LinkedBlockingQueue一样,put和take是一个阻塞的方法,直到插入成功。这里不再赘述,有兴趣的可以看上一篇文章。
- offer 代码很简单,我们重点关注enqueue(e)入队方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public boolean offer(E e) {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count == items.length)
return false;
else {
enqueue(e); // 入队操作
return true;
}
} finally {
lock.unlock();
}
} - enqueue dequeue出队操作也类似,从上面代码中可以看到,它是使用了putIndex、takeIndex对数组的循环操作,来实现队列。
1
2
3
4
5
6
7
8private void enqueue(E x) {
final Object[] items = this.items;
items[putIndex] = x;
if (++putIndex == items.length) // 如果已经是最后索引了,则下标改为0
putIndex = 0;
count++;
notEmpty.signal();
} - 其他方法类似size,contains方法都是使用锁,所以也都是精确的。