JAVA无阻塞先进先出的队列_Java并发Concurrent包——ArrayBlockingQueue源码分析

ArrayBlockingQueue 是一个由数组支持的有界阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。

BlockingQueue 接口实现的都是阻塞队列。而 ConcurrentLinkedQueue 是基于 CAS 和链表实现的无阻塞高性能队列。

ConcurrentLinkedQueue 的源码分析见 Java并发Concurrent包——ConcurrentLinkedQueue源码分析

这是一个典型的“有界缓存区”,固定大小的数组在其中保持生产者插入的元素和使用者提取的元素。一旦创建了这样的缓存区,就不能再增加其容量。试图向已满队列中放入元素会导致操作受阻塞;试图从空队列中提取元素将导致类似阻塞。

属性

// 底层对象数组

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 ArrayBlockingQueue(int capacity, boolean fair) {

if (capacity <= 0)

throw new IllegalArgumentException();

// 初始化底层数组

this.items = new Object[capacity];

// 新建公平或非公平锁,和两个condition

lock = new ReentrantLock(fair);

notEmpty = lock.newCondition();

notFull = lock.newCondition();

}

重要方法

offer(E 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方法,下面分析

enqueue(e);

return true;

}

} finally {

lock.unlock();

}

}

enqueue(E x)

// 只在当前线程拥有锁的时候调用

private void enqueue(E x) {

final Object[] items = this.items;

// 在入队下标处放入新元素

items[putIndex] = x;

// 下标加1后,判断是否等于数组总长度,如果是将putIndex置为0

if (++putIndex == items.length)

putIndex = 0;

// 有效元素个数加1

count++;

// 唤醒其他基于此condition的线程

notEmpty.signal();

}

poll()

public E poll() {

final ReentrantLock lock = this.lock;

lock.lock();

try {

// 有效元素不为0就可以调用dequeue方法出列

return (count == 0) ? null : dequeue();

} finally {

lock.unlock();

}

}

dequeue()

// 只在当前线程拥有锁的时候调用

private E dequeue() {

final Object[] items = this.items;

@SuppressWarnings("unchecked")

// 保存出队下标处的元素

E x = (E) items[takeIndex];

// 将该下标处置为null

items[takeIndex] = null;

// 如果也走到尽头,从0开始

if (++takeIndex == items.length)

takeIndex = 0;

// 有效元素个数减1

count--;

//

if (itrs != null)

itrs.elementDequeued();

// 队列不再满,发信号给其他线程

notFull.signal();

// 返回出队的对象

return x;

}

take()

获取并移除此队列的头部,在元素变得可用之前一直等待(如果有必要)。

public E take() throws InterruptedException {

final ReentrantLock lock = this.lock;

lock.lockInterruptibly();

try {

// 如果可用元素为空,则等待notEmpty这个condition的信号

// 直到出现不为空时,进行出队操作

while (count == 0)

notEmpty.await();

return dequeue();

} finally {

lock.unlock();

}

}

put(E e)

将指定的元素插入此队列的尾部,如果该队列已满,则等待可用的空间。和 take 方法对应。

public void put(E e) throws InterruptedException {

checkNotNull(e);

final ReentrantLock lock = this.lock;

lock.lockInterruptibly();

try {

// 如果元素已满,则线程阻塞等待出现notFull的情况,才能入队

while (count == items.length)

notFull.await();

enqueue(e);

} finally {

lock.unlock();

}

}

该类的代码比较简单易懂。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值