这个就有点难度了
阻塞队列简单分析
public class ArrayBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, java.io.Serializable {
//存放数据的object类型的数组
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;
//锁
final ReentrantLock lock;
/** Condition for waiting takes */
//等待取出数据的条件
private final Condition notEmpty;
/** Condition for waiting puts */
//等待放入数据的条件
private final Condition notFull;
/**
* Shared state for currently active iterators, or null if there
* are known not to be any. Allows queue operations to update
* iterator state.
*/
//迭代器 后面仔细看他的作用
transient Itrs itrs = null;
/**
* Circularly decrement i. 循环减量 暂时还不知道有什么用
*/
final int dec(int i) {
return ((i == 0) ? items.length : i) - 1;
}
//构造函数 指定了队列的容量与锁的类型 (公平锁还是非公平锁)
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();
}
public ArrayBlockingQueue(int capacity, boolean fair, Collection<? extends E> c) {
this(capacity, fair);
//获取到对象初始化时创建的锁
final ReentrantLock lock = this.lock;
//加锁
lock.lock(); // Lock only for visibility, not mutual exclusion
try {
//记录队列大小的标识
int i = 0;
try {
//遍历传入的集合
for (E e : c) {
//判断集合中是否有null值存储 有的话 抛空指针
checkNotNull(e);
//将集合中的数据加入队列
items[i++] = e;
}
//如果传入的集合的大小比队列容量大,抛异常
} catch (ArrayIndexOutOfBoundsException ex) {
throw new IllegalArgumentException();
}
//设置队列大小
count = i;
//记录下一次将要入队列的数据的索引
putIndex = (i == capacity) ? 0 : i;
} finally {
//释放锁
lock.unlock();
}
}
//添加数据 调用super.add(),实则是调用了下面的offer()
public boolean add(E e) {
return super.add(e);
}
//添加数据的真正的实现
public boolean offer(E e) {
//检验数据不为null
checkNotNull(e);
//获取锁
final ReentrantLock lock = this.lock;
//加锁
lock.lock();
try {
//判断队列是否已满
if (count == items.length)
return false;
else {
//队列未满,入队列
enqueue(e);
return true;
}
} finally {
//释放锁
lock.unlock();
}
}
public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException {
checkNotNull(e);
//超时时间
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
//如果队列已满,并且设置了正确的阻塞时间,那么等到了指定的时间就是停止休眠
//相比于await,它可以设置指定时间之后就激活线程,其他的线程也同时可以唤醒这两种方式下的休眠的线程
while (count == items.length) {
//如果时间<0直接返回错误
if (nanos <= 0)
return false;
//阻塞指定的时间
nanos = notFull.awaitNanos(nanos);
}
//数据入队列
enqueue(e);
return true;
} finally {
lock.unlock();
}
}
//数据出队列
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
//当队列为空时直接返回null,否则将队列最前的数据弹出队列
return (count == 0) ? null : dequeue();
} finally {
lock.unlock();
}
}
//数据出队列
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
//当队列为空时阻塞,直到队列有数据 然后再将数据弹出队列
while (count == 0)
notEmpty.await();
return dequeue();
} 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 {
//当队列为空的时候,休眠一定的时间。再判断队列是否有数据可以出队列
while (count == 0) {
if (nanos <= 0)
return null;
nanos = notEmpty.awaitNanos(nanos);
}
return dequeue();
} finally {
lock.unlock();
}
}
//获取队列头的数据
public E peek() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
//只获取,并不出队列
return itemAt(takeIndex); // null when queue is empty
} finally {
lock.unlock();
}
}
//给队列中添加数据
public void put(E e) throws InterruptedException {
//非null校验
checkNotNull(e);
//获取锁
final ReentrantLock lock = this.lock;
//这一块是java并发包获取锁的核心逻辑 后续仔细分析
lock.lockInterruptibly();
try {
//判断队列是否已满
while (count == items.length)
//队列阻塞
notFull.await();
//数据入队列
enqueue(e);
} finally {
//释放锁
lock.unlock();
}
}
//获取队列剩余的容量
public int remainingCapacity() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return items.length - count;
} finally {
lock.unlock();
}
}
public boolean remove(Object o) {
if (o == null) return false;
final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count > 0) {
final int putIndex = this.putIndex;
int i = takeIndex;
//如果当前队列有指定索引的值,那么就移除, 否则 判断移除的是否是下一次插入的索引,不是的话再尝试移除,是的话直接退出,返回false
do {
if (o.equals(items[i])) {
removeAt(i);
return true;
}
//如果索引超出队列下标,将其设置为0 然后进入下一次的尝试移除操作
if (++i == items.length)
i = 0;
} while (i != putIndex);
}
return false;
} finally {
lock.unlock();
}
}
void removeAt(final int removeIndex) {
// assert lock.getHoldCount() == 1;
// assert items[removeIndex] != null;
// assert removeIndex >= 0 && removeIndex < items.length;
final Object[] items = this.items;
//如果移除的索引是下一次移除的索引 做出队操作
if (removeIndex == takeIndex) {
// removing front item; just advance
items[takeIndex] = null;
if (++takeIndex == items.length)
takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
} else {
// an "interior" remove
// 将给定索引的值移除,并将后面的数据全部前移 将putIndex也前移
final int putIndex = this.putIndex;
for (int i = removeIndex;;) {
int next = i + 1;
if (next == items.length)
next = 0;
if (next != putIndex) {
items[i] = items[next];
i = next;
} else {
items[i] = null;
this.putIndex = i;
break;
}
}
count--;
if (itrs != null)
itrs.removedAt(removeIndex);
}
notFull.signal();
}
//返回指定索引的数据
final E itemAt(int i) {
return (E) items[i];
}
//数据入队列
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++;
//随机唤醒一个等待取数据的线程
notEmpty.signal();
}
//数据出队列
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;
}
}```