ArrayBlockingQueue 实际实现是一个环形数组,并且保护了线程安全,那么是如何保证线程安全的?
环形数组怎么实现的?
先看下里面的几个参数是干嘛的
/** The queued items */
数据,存数据的
final Object[] items;
/** items index for next take, poll, peek or remove */
取出的引索
int takeIndex;
/** items index for next put, offer, or add */
放置的引索
int putIndex;
/** Number of elements in the queue */
实际上有几个数据,为什么会有这个东西,因为实际实现是环形数组,但是这只是个概念
int count;
/*
* Concurrency control uses the classic two-condition algorithm
* found in any textbook.
*/
/** Main lock guarding all access */
默认的非公平锁,支持公平锁
final ReentrantLock lock;
/** Condition for waiting takes */
空锁
private final Condition notEmpty;
/** Condition for waiting puts */
满锁
private final Condition notFull;
?ArrayBlockingQueue 实际实现是一个环形数组 先看下它咋实现的
private void enqueue(E x) {
// assert lock.getHoldCount() == 1;
// assert items[putIndex] == null;
拿到局部变量防止并发
final Object[] items = this.items;
将数据放入数组
items[putIndex] = x;
如果到头了反回到尾节点
if (++putIndex == items.length) putIndex = 0;
真实数量++
count++;
非空锁解锁,take方法此时可以继续执行了
notEmpty.signal();
}
/**
* Inserts the specified element at the tail of this queue, waiting
* for space to become available if the queue is full.
*
* @throws InterruptedException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
public void put(E e) throws InterruptedException {
Objects.requireNonNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
如果数据相等证明满了,锁住不放
while (count == items.length)
notFull.await();
enqueue(e);
} finally {
lock.unlock();
}
}
?offer如果队列满了会抛弃掉,offer方法如果满了会锁住挂起等到加入为止
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
如果 == 0 证明没数据了,等有数据再解开循环
notEmpty.await();
return dequeue();
} finally {
lock.unlock();
}
}
/**
* Extracts element at current take position, advances, and signals.
* Call only when holding lock.
*/
private E dequeue() {
// assert lock.getHoldCount() == 1;
// assert items[takeIndex] != null;
final Object[] items = this.items;
@SuppressWarnings("unchecked")
取出数据
E x = (E) items[takeIndex];
把当前节点置空
items[takeIndex] = null;
走向下一个节点
if (++takeIndex == items.length) takeIndex = 0;
数据量-1
count--;
if (itrs != null)
itrs.elementDequeued();
解锁
notFull.signal();
return x;
}
环形数组示例图片嘛,大概这样