千家信息网

JUC的ArrayBlockingQueue怎么实现数据的添加和拿取

发表于:2026-10-31 作者:千家信息网编辑
千家信息网最后更新 2026年10月31日,本篇内容主要讲解"JUC的ArrayBlockingQueue怎么实现数据的添加和拿取",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"JUC的ArrayBl
千家信息网最后更新 2026年10月31日JUC的ArrayBlockingQueue怎么实现数据的添加和拿取

本篇内容主要讲解"JUC的ArrayBlockingQueue怎么实现数据的添加和拿取",感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习"JUC的ArrayBlockingQueue怎么实现数据的添加和拿取"吧!

ArrayBlockingQueue 有以下几个特点:

  • 由数组实现的有界阻塞队列,容量一旦创建,后续大小无法修改;

  • 遵照先进先出规则,队头拿数据,队尾取数据;

  • 跟 LinkedBlockingQueue 一样,队列满时,往队列中 put 数据会被阻塞,队列空时,往队列中拿数据会被阻塞;

  • 对数据操作时,共用一把锁,所以不能同时读写操作;

ArrayBlockingQueue 跟 LinkedBlockingQueue 一样,同样继承了 AbstractQueue 实现 BlockingQueue 接口,所以在方法上跟 LinkedBlockingQueue 一样,所以在这里我们不把方法列出来了,可以去查看前面 LinkedBlockingQueue 的文章~

除了方法之外,在 ArrayBlockingQueue 中,还有两个比较重要的参数:

/** items index for next take, poll, peek or remove */
// 获取元素的位置
int takeIndex;
/** items index for next put, offer, or add */
// 新增元素时的数组下标
int putIndex;

由于 ArrayBlockingQueue 底层采用的是数组,结合上面的两个参数,ArrayBlockingQueue 的整体结构图大概如下:

ArrayBlockingQueue 有三个构造函数:


public ArrayBlockingQueue(int capacity);
// fair 表示是否为公平锁
public ArrayBlockingQueue(int capacity, boolean fair);

public ArrayBlockingQueue(int capacity, boolean fair, Collection c);

关于构造函数就不多说了,都大同小异,跟 LinkedBlockingQueue 一样,同样拿 put()、take() 方法,看看 ArrayBlockingQueue 是如何实现数据的添加和拿取的~

先从put()方法开始,看看 ArrayBlockingQueue 是如何实现的~

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();
}
}
// 入队
private void enqueue(E e) {
final Object[] items = this.items;
// 根据 putIndex 插入到对应的位置即可
items[putIndex] = e;
// 设置好下一次插入的位置,如果当前插入的位置是最后一个元素,
// 那么下一次插入的位置就是队头了
if (++putIndex == items.length) putIndex = 0;
count++;
notEmpty.signal();
}

put() 方法的实现并不复杂,代码也就 20 行左右,我们来拆解一下 put 过程:

  • 1、先获取锁,对操作进行加锁;

  • 2、判断队列是否队满,如果队满,则挂起等待;

  • 3、根据 putIndex 的值,直接将元素插入到 items 数组中;

  • 4、调整 putIndex 的位置,用于下一次插入使用,如果当前 putIndex 是数组的最后一个位置,则 putIndex 下一次插入的位置是数组的第一个位置,可以把它当作是循环;

  • 5、解锁;

put 方整体解决起来不难,跟 LinkedBlockingQueue 一样,其他添加方法这里就不介绍了,大同小异~

再来看看 ArrayBlockingQueue 是如何实现 take() 方法的,take() 方法主要源码如下:


public E take() throws InterruptedException {
// 获取锁
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
// 判断队列是否为空,为空的话挂起等待
while (count == 0)
notEmpty.await();
// 获取数据
return dequeue();
} finally {
lock.unlock();
}
}
private E dequeue() {

final Object[] items = this.items;
@SuppressWarnings("unchecked")
// 根据 takeIndex 获取 items 中的元素
E e = (E) items[takeIndex];
// 将 takeIndex 中的数据置为空
items[takeIndex] = null;
// 设置下一次获取数据的下标,
if (++takeIndex == items.length) takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
notFull.signal();
return e;
}

take() 方法跟 put() 方法没有什么太大的区别,就是一个反操作~

最后我们再来关注一下 remove() 方法,这个方法还是有一些学问的,主要源码如下:


public boolean remove(Object o) {
if (o == null) return false;
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count > 0) {
final Object[] items = this.items;
for (int i = takeIndex, end = putIndex,
to = (i < end) ? end : items.length;
; i = 0, to = end) {
// 遍历有值的一段数据
for (; i < to; i++)
if (o.equals(items[i])) {
removeAt(i);
return true;
}
if (to == end) break;
}
}
return false;
} finally {
lock.unlock();
}
}
// 主要看这个方法
void removeAt(final int removeIndex) {
final Object[] items = this.items;
// 如果要删除的位置正好是下一次 take的位置
if (removeIndex == takeIndex) {
// removing front item; just advance
items[takeIndex] = null;
if (++takeIndex == items.length) takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
} else {
// 如果删除的位置时 takeIndex 和 putIndex 之间的位置,则被删除的数据全部往前移动~
for (int i = removeIndex, putIndex = this.putIndex;;) {
int pred = i;
if (++i == items.length) i = 0;
if (i == putIndex) {
items[pred] = null;
this.putIndex = pred;
break;
}
items[pred] = items[i];
}
count--;
if (itrs != null)
itrs.removedAt(removeIndex);
}
notFull.signal();
}

remove 的时候分三种情况:

  • 第一种:当 removeIndex == takeIndex 时,这种情况就比较简单,将该位置的元素删除后,takeIndex +1 即可;

  • 第二种:当 removeIndex + 1 == putIndex 时,直接将 putIndex -1 就好,相当于 putIndex 指针往前移动一格;

  • 第三种:当 removeIndex != takeIndex && removeIndex + 1 != putIndex 时,这种情况就比较复杂了,需要涉及到数据的移动,要将 removeIndex 后面的数据全部往前移动一个位置,putIndex 的位置也要迁移一位,具体的可以参考源码;

到此,相信大家对"JUC的ArrayBlockingQueue怎么实现数据的添加和拿取"有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

数据 位置 方法 队列 数组 元素 移动 阻塞 情况 源码 复杂 大同小异 下标 两个 内容 函数 参数 就是 整体 大同 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 科技互联网 南京欣网互联网络科技 湖南永感互联网科技有限公司 互联网品科技 美国互联网科技巨头监管 深圳天众互联网科技公司 互联网 视角下的科技创新 互联网科技英文翻译 联恩商钥互联网科技有限公司 北京三清互联网科技 互联网之后的科技是什么 央行互联网金融科技公司 欧洲十大科技互联网公司 互联网第三次科技革命特征 每天都有哪些好的互联网科技 互联网领先科技宣传片 互联网科技企业商标注意事项 陕西九四连强互联网科技有限公司 长沙渺峰互联网科技有限公司 互联网科技博主张洲 关于新基建和互联网科技 中国 科技 互联网 互联网科技视频 北京禾田雨橡互联网科技 互联网科技公司的市场部门 汽车互联网创新科技园 互联网科技和信息 翼展科技 首家互联网医院 上海京穆互联网科技有限公司 现代科技的标志之一的互联网
0