我的编程空间,编程开发者的网络收藏夹
学习永远不晚

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

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

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

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

ArrayBlockingQueue 有以下几个特点:

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

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

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

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

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

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


// 获取元素的位置
int takeIndex;

// 新增元素时的数组下标
int putIndex;

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

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

ArrayBlockingQueue 有三个构造函数:


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

public ArrayBlockingQueue(int capacity, boolean fair, Collection<? extends E> 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 过程:

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

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

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

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

  • 解锁;

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怎么实现数据的添加和拿取”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

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

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

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

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

JavaWeb如何实现mysql数据库数据的添加和删除

这篇文章主要为大家展示了“JavaWeb如何实现mysql数据库数据的添加和删除”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“JavaWeb如何实现mysql数据库数据的添加和删除”这篇文章吧。
2023-06-29

C++文件的数据写入和文件的数据读取怎么实现

这篇文章主要介绍了C++文件的数据写入和文件的数据读取怎么实现的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C++文件的数据写入和文件的数据读取怎么实现文章都会有所收获,下面我们一起来看看吧。一:没有数据,准备
2023-07-02

PHP怎么实现获取MySQL数据库的记录数据

这篇文章主要介绍PHP怎么实现获取MySQL数据库的记录数据,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!获取数据表的记录总数
2023-06-29

PHP怎么实现添加或减去特定日期的天数

本篇内容介绍了“PHP怎么实现添加或减去特定日期的天数”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!本文的主题是“如何编写一个 PHP 脚本
2023-06-20

MySql中索引的添加删除语句代码实现,原则和数据结构

什么是索引在现实生活中,我们经常去图书馆查阅图书。现在我们将所有图书杂乱无章的摆放在一起,那么找一本书就像大海捞针一样效率非常低。如果我们按分类整理排序后,根据类别去找对应的图书那么效率就很高了。其实这个过程就是在建立索引。查看mysql中语句执行效率show
MySql中索引的添加删除语句代码实现,原则和数据结构
2014-05-31

Android实现动态添加数据与堆叠折线图的方法是什么

本篇内容介绍了“Android实现动态添加数据与堆叠折线图的方法是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!效果视频引用描述本示例采
2023-06-25

java怎么实现数据的输入和输出

在Java中,可以使用Scanner类来实现数据的输入和使用System.out.println()方法来实现数据的输出。以下是一个简单的示例代码,演示了如何使用Scanner类实现数据的输入和使用System.out.println()
2023-10-27

Redis怎么实现数据的备份和恢复

Redis可以通过以下几种方式实现数据的备份和恢复:RDB持久化:Redis可以将内存中的数据定期或者根据配置的条件写入磁盘文件中,这个文件就是RDB快照文件。通过配置save指令可以设置生成快照文件的条件,通过bgsave指令可以手动触发
Redis怎么实现数据的备份和恢复
2024-05-07

Beam怎么实现数据的实时压缩和存储

要实现数据的实时压缩和存储,可以使用Apache Beam来构建数据处理流水线。Apache Beam是一个用于并行化、扩展和优化数据处理任务的开源流式数据处理框架。以下是如何使用Apache Beam来实现数据的实时压缩和存储的步骤:创
Beam怎么实现数据的实时压缩和存储
2024-05-11

vertica数据库copy命令是实现数据加载的代码怎么写

vertica数据库copy命令是实现数据加载的代码怎么写,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。vertica数据加载创建外部数据文本:[dbadmin
2023-06-02

Redis怎么实现数据的压缩和解压缩

Redis可以通过以下方式实现数据的压缩和解压缩:使用Redis的压缩功能:Redis可以通过配置选项来启用对数据的压缩功能。通过配置redis.conf文件中的rdbcompression选项为yes,可以启用RDB文件的压缩功能,从而减
Redis怎么实现数据的压缩和解压缩
2024-05-07

Atlas怎么实现数据的归档和长期存储

Atlas可以通过以下两种方式实现数据的归档和长期存储:使用Atlas Data Lake:Atlas Data Lake是Atlas的一个功能,它可以将数据存储在云端的数据湖中,以便对数据进行长期存储和归档。用户可以将数据直接导入Atla
Atlas怎么实现数据的归档和长期存储
2024-05-11

Redis怎么实现数据的自动扩展和收缩

Redis通过使用内存碎片整理和数据淘汰策略来实现数据的自动扩展和收缩。内存碎片整理:Redis会定期进行内存碎片整理,将散落在内存中的小块空闲内存合并成更大的连续内存块,从而提高内存的利用率。这样可以确保Redis在存储大量数据时能够更高
Redis怎么实现数据的自动扩展和收缩
2024-05-07

jquery怎么实现输入框数字的增加和减少功能

jquery输入框数字增加在Web开发中,经常会用到输入框的数字增加和减少功能,例如购物车数量、商品数量等。本文将介绍如何利用jquery实现输入框数字的增加和减少功能。代码实现:首先,需要引入jquery库文件:```<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>```接着,
2023-05-14

Cassandra数据的分布式聚合和计算怎么实现

Cassandra是一个分布式数据库系统,可以通过将数据分布在多个节点上来实现分布式聚合和计算。以下是实现分布式聚合和计算的一些常见方法:使用Cassandra的查询语言CQL进行聚合和计算:可以使用CQL语句来对分布在多个节点上的数据进行
Cassandra数据的分布式聚合和计算怎么实现
2024-05-11

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录