Java并发基础:BlockingQueue和BlockingDeque接口的区别?

Java并发基础:BlockingQueue和BlockingDeque接口的区别? - 程序员古德

核心概念

BlockingQueueBlockingDeque 它们都支持在并发编程中的线程安全操作,但是,这两个接口之间存在一些关键的区别,主要在于它们所支持的操作和数据结构的特性,如下:

1、数据结构特性

  1. BlockingQueue 是一个支持线程安全的队列,即它遵循 FIFO(先进先出)原则,可以向队列的尾部添加元素,并从队列的头部移除元素。
  2. BlockingDeque 是一个支持线程安全的双端队列(Deque,也称为双头队列),因此,可以在队列的头部和尾部添加或移除元素,BlockingDeque 提供了比 BlockingQueue 更多的操作灵活性。

2、操作

  1. BlockingQueue 提供了基本的队列操作,如 add(), offer(), put(), take(), poll() 等,这些方法主要用于在队列的尾部添加元素和从队列的头部移除元素。
  2. BlockingDeque 除了提供与 BlockingQueue 类似的操作外(但通常是以不同的名称提供,例如 offerFirst(), offerLast(), takeFirst(), takeLast() 等),还支持在队列的头部进行添加和移除操作的方法,如 offerFirst(), pollFirst(), peekFirst() 等,此外,它还提供了 push(), pop() 等栈操作,因为双端队列可以模拟栈的行为。

3、使用场景

  1. 当需要一个简单的、线程安全的 FIFO 队列时,BlockingQueue 是一个很好的选择,它通常用于生产者-消费者场景,其中生产者将数据放入队列,消费者从队列中取出数据。
  2. 当需要更多的灵活性,例如在队列的头部和尾部都能添加或移除元素时,BlockingDeque 是一个更好的选择,这种数据结构在需要同时维护队列和栈行为的场景中特别有用。

4、实现类

  1. BlockingQueue 提供了多种实现,如 ArrayBlockingQueue, LinkedBlockingQueue, PriorityBlockingQueue, SynchronousQueue 等。
  2. BlockingDeque,常见的实现是 LinkedBlockingDeque,这个实现提供了一个基于链表的双端队列,支持在队列的两端进行高效的插入和移除操作。

代码案例

Java并发基础:BlockingQueue和BlockingDeque接口的区别? - 程序员古德

BlockingQueue

BlockingQueue 接口表示一个可以存取元素,并且线程安全的队列,换句话说,多个线程可以同时从这个队列中安全地插入或者移除元素,BlockingQueue 的特性在于它支持在队列为空时,获取元素的线程将会等待,直到有元素可获取;当队列已满时,试图插入元素的线程将会等待,直到队列中有可用的空间,它的主要功能如下:

  1. 线程安全BlockingQueue 的所有操作都是线程安全的,这意味着在多线程环境中,可以安全地添加或移除元素,而不需要额外的同步措施。
  2. 阻塞操作:当队列为空时,从队列中获取元素的线程将会被阻塞,直到其他线程向队列中插入元素,同样,当队列已满时,试图插入元素的线程也会被阻塞,直到队列中有空间可用。
  3. 支持限时等待:除了无限期的等待外,BlockingQueue 还提供了带有超时参数的方法,允许线程在指定的时间内等待元素的插入或移除。
  4. 容量可选BlockingQueue 的实现类可以选择有界或无界,有界队列有一个固定的容量,而无界队列的容量则只受限于可用内存。

它有以下使用场景:

  1. 生产者-消费者模式:这是 BlockingQueue 最常见的使用场景,在这种模式中,生产者线程生成数据并将其放入队列,而消费者线程从队列中取出数据并处理,BlockingQueue 简化了生产者-消费者模式的实现,因为它负责处理线程间的同步和通信。
  2. 任务调度BlockingQueue 也可以用于任务调度系统中,在这种情况下,可以将待处理的任务作为元素添加到队列中,然后由工作线程从队列中取出任务并处理。
  3. 缓冲:在需要缓冲数据流或事件流的系统中,BlockingQueue 可以作为缓冲区使用,它允许数据或事件的生产者和消费者以不同的速率运行,而不会丢失数据或造成拥塞。
  4. 线程池:在 ExecutorService 框架中,BlockingQueue 用于存储待执行的任务,线程池中的工作线程从队列中取出任务并执行。

下面是一个简单的生产者-消费者示例,展示了如何使用 BlockingQueue,如下代码:

import java.util.concurrent.BlockingQueue;  
import java.util.concurrent.LinkedBlockingQueue;  public class ProducerConsumerExample {  public static void main(String[] args) {  BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(5);  // 生产者线程  Thread producer = new Thread(() -> {  for (int i = 0; i < 10; i++) {  try {  System.out.println("生产者生产了 " + i);  queue.put(i); // 如果队列满了,将会阻塞  Thread.sleep(200); // 模拟生产时间  } catch (InterruptedException e) {  e.printStackTrace();  }  }  });  // 消费者线程  Thread consumer = new Thread(() -> {  for (int i = 0; i < 10; i++) {  try {  Integer item = queue.take(); // 如果队列为空,将会阻塞  System.out.println("消费者消费了 " + item);  Thread.sleep(500); // 模拟消费时间  } catch (InterruptedException e) {  e.printStackTrace();  }  }  });  // 启动线程  producer.start();  consumer.start();  }  
}

BlockingDeque

BlockingDeque结合了BlockingQueue的阻塞特性和Deque(双端队列)的双端操作能力,从而提供了一个线程安全的、支持在两端添加和移除元素的阻塞队列,它有以下主要功能:

  1. 线程安全BlockingDeque的所有操作都是线程安全的,因此多个线程可以安全地同时访问它。
  2. 阻塞操作:如果队列为空,尝试从队列中取出元素的线程将会被阻塞,直到其他线程向队列中插入元素,同样,如果队列已满(对于有界队列),尝试插入元素的线程也会被阻塞,直到队列中有空间可用。
  3. 双端操作:与普通的Deque一样,BlockingDeque支持在队列的两端添加(addFirst, addLast, offerFirst, offerLast)和移除元素(removeFirst, removeLast, pollFirst, pollLast),此外,它还提供了检查队列两端元素的方法(getFirst, getLast, peekFirst, peekLast)。
  4. 容量可选BlockingDeque的实现类可以选择有界或无界,有界队列有一个固定的容量,而无界队列的容量则只受限于可用内存。

它有以下使用场景:

  1. 生产者-消费者模式:这是BlockingDeque最常见的使用场景之一,生产者线程在队列的一端添加元素,而消费者线程在另一端移除元素,这种模式特别适用于需要缓冲数据流或任务队列的系统。
  2. 工作窃取算法:在并行计算中,BlockingDeque可以用作工作窃取队列,实现工作线程之间的任务分配,当一个线程完成了自己的任务时,它可以从其他线程的任务队列中“窃取”任务来执行。
  3. 双端操作的需求:任何需要在队列的两端进行添加和移除操作的并发场景都可以使用BlockingDeque,例如,实现一个并发的LRU(最近最少使用)缓存时,可能需要使用BlockingDeque来维护访问顺序。

下面是一个使用BlockingDeque的简单生产者-消费者示例,如下代码:

import java.util.concurrent.BlockingDeque;  
import java.util.concurrent.LinkedBlockingDeque;  public class ProducerConsumerWithBlockingDeque {  public static void main(String[] args) {  BlockingDeque<Integer> deque = new LinkedBlockingDeque<>(5);  // 生产者线程  Thread producer = new Thread(() -> {  for (int i = 0; i < 10; i++) {  try {  System.out.println("生产者生产了 " + i);  deque.putFirst(i); // 在队列头部插入元素,如果队列满了,将会阻塞  Thread.sleep(200); // 模拟生产时间  } catch (InterruptedException e) {  e.printStackTrace();  }  }  });  // 消费者线程  Thread consumer = new Thread(() -> {  for (int i = 0; i < 10; i++) {  try {  Integer item = deque.takeLast(); // 从队列尾部移除元素,如果队列为空,将会阻塞  System.out.println("消费者消费了 " + item);  Thread.sleep(500); // 模拟消费时间  } catch (InterruptedException e) {  e.printStackTrace();  }  }  });  // 启动线程  producer.start();  consumer.start();  }  
}

在这个示例中,创建了一个容量为5的LinkedBlockingDeque,生产者线程在队列的头部插入整数,而消费者线程在队列的尾部移除整数,注意,当队列满时,生产者线程会被阻塞;同样,当队列空时,消费者线程也会被阻塞,此外,使用putFirsttakeLast方法来演示双端队列的特性,也可以使用putLasttakeFirst来改变插入和移除元素的顺序。

关注我,每天学习互联网编程技术 - 程序员古德

END!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/673464.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

npm 上传一个自己的应用(4) 更新自己上传到NPM中的工具版本 并就行内容修改

前面 npm 上传一个自己的应用(2) 创建一个JavaScript函数 并发布到NPM 我们讲了将自己写的一个函数发送到npm上 那么 如果我们想到更好的方案 希望对这个方法进行修改呢&#xff1f; 比如 我们这里加一个方法 首先 我们还是要登录npm npm login然后 根据要求填写 Username 用…

HDFS 之 数据管理(namespace 和 slaves)

1、namespace Namespace在HDFS中是一个非常重要的概念,也是有效管理数据的方法。Namespace有很多优点:可伸缩性。使HDFS集群存储能力可以轻松进行水平拓展;系统性能。单点性能受限,影响系统吞吐;隔离性。不同业务类型访问集群有时容易互相干扰,使用多Namespace可以有效管…

BlueLotus 下载安装使用

说明 蓝莲花平台BlueLotus&#xff0c;是清华大学曾经的蓝莲花战队搭建的平台&#xff0c;该平台用于接收xss返回数据。 正常执行反射型xss和存储型xss&#xff1a; 反射型在执行poc时&#xff0c;会直接在页面弹出执行注入的poc代码&#xff1b;存储型则是在将poc代码注入用…

如何在 emacs 上开始使用 Tree-Sitter(windows)

文章目录 如何在emacs上开始使用Tree-Sitter&#xff08;windows&#xff09; 如何在emacs上开始使用Tree-Sitter&#xff08;windows&#xff09; 参考&#xff1a;“How to Get Started with Tree-Sitter”。 首先要有一个可运行的emacs&#xff0c;并且它支持Tree-Sitter&…

Docker配置Portainer容器管理界面

目录 一、Portainer 简介 优点&#xff1a; 缺点&#xff1a; 二、环境配置 1. 拉取镜像 2. 创建启动容器 三、操作测试 1. 进入容器 2. 拉取镜像并部署 3. 访问测试 一、Portainer 简介 Portainer 是一个开源的轻量级容器管理界面&#xff0c;用于管理 Docker 容器…

图数据库 之 Neo4j - 环境搭建(2)

运行环境&#xff1a; centos7 Docker version 18.09.6 下载镜像 docker search neo4j docker pull neo4j 创建 neo4j 用户 # 创建 neo4j 用户 # -M 不创建用户的主目录 sudo useradd -M neo4j # usermod 用于修改用户属性命令 # -L 锁定用户&#xff0c;用户无法登录系统 user…

【知识图谱--第二讲知识图谱的表示】

知识图谱的表示 知识表示Knowledge Representation 知识表示方法知识图谱的符号表示基于图的知识表示与建模简单图建模-最简单的无向图有向标记图OWL与Ontology 知识图谱的向量表示 知识表示 Knowledge Representation 知识表示&#xff08;KR&#xff09;就是用易于计算机处…

深度测评:ONLYOFFICE 桌面编辑器 v8.0新功能

目录 前言 一、PDF表单处理&#xff1a;提升办公效率 二、RTL&#xff08;从右到左&#xff09;支持&#xff1a;满足不同语言习惯 三、Moodle集成&#xff1a;教育行业的新助力 四、本地界面主题&#xff1a;个性化办公体验 五、性能优化与稳定性提升 六、性能与稳定性…

数据链路层DoS

图9-14 集线器应用原理 数据链路层中拒绝服务攻击的方式一般很少为人所熟知。数据链路层拒绝服 务攻击的主要目标为二层交换机。在早期网络中&#xff0c;通常都会使用集线器作为中间 处理设备。集线器属于纯硬件网络底层设备&#xff0c;没有任何“ 智能记忆” 能力和“学 …

Airtest实现在手机界面快速批量采集数据

Airtest实现在手机界面快速批量采集数据 一、问题 Airtest使用的poco方法比较慢,寻找差不多一周,看完这篇文章能节省一周时间,希望帮到大家。二、解决思路 使用Airtest图像识别,这样就会速度上提升效率。 三、解决办法 使用页面规律,要找到每条数据的附近规律(一般是图…

发廊理发店微信小程序展示下单前端静态模板源码

模板描述&#xff1a;剪发小程序前端源码&#xff0c;一共五个页面&#xff0c;包括店铺、理发师、订单、我的等页面 注&#xff1a;该源码是前端静态模板源码&#xff0c;没有后台和API接口

PCIE和USB 耦合电容放置位置记录- 一般放置在TX端

PCIE耦合电容位置 以下为引用内容&#xff0c;为记录而做的本篇文章&#xff1a; 1、PCIe标准里面明确规定&#xff1a;当两个设备通过连接器互联时&#xff0c;必须放置交流耦合电容到TX端&#xff1b; 2、放远放近最大的不同时高速信号传输中的介质损耗和趋肤效应不同&#…

【Git】08 多人单分支协作场景

文章目录 一、场景1&#xff1a;不同人修改不同文件1.1 场景描述1.2 场景复现1.2.1 克隆到本地1.2.2 新建分支1.2.3 B修改、提交与推送1.2.4 A修改与提交1.2.5 B再次修改并推送1.2.6 A推送报错 1.3 解决 二、场景2&#xff1a;不同人修改同文件的不同区域2.1 场景描述2.2 场景复…

计算机网络概念、组成、功能和分类

文章目录 概要1.怎么学习计算机网络2.概念3.功能、组成4.工作方式、功能组成5.分类 概要 概念、组成、功能和分类 1.怎么学习计算机网络 2.概念 通信设备&#xff1a;比如路由器、路由器 线路&#xff1a;将系统和通信设备两者联系的介质之类的 计算机网络是互连的、自治的的计…

如何设计一个预约抢购活动

总体架构设计 互联网大量数据的存储设计 1&#xff09;哈希算法&#xff0c;对商品ID进行分片 节点取模的形式&#xff0c;优点是均匀分布&#xff0c;缺点是扩展性不好。所以&#xff0c;我们可以采用一致性hash。 一致性HASH的优点&#xff1a; 解决单一热点问题&#xf…

3060ti显卡+cuda12.1+win10编译安装生成fastdeploy的c++与python库

在cuda12中,调用官方发布的fastdeploy会出现报错,故此自行编译fastdeploy库。 官网编译教程:https://github.com/PaddlePaddle/FastDeploy/blob/develop/docs/cn/build_and_install/gpu.md 可选编译选项 编译选项 无论是在何平台编译,编译时仅根据需求修改如下选项,勿…

分布式springboot 3项目集成mybatis官方生成器开发记录

文章目录 说明实现思路实现步骤第一步&#xff1a;创建generator子模块第二步&#xff1a;引入相关maven插件和依赖第三步&#xff1a;编写生成器配置文件第四步&#xff1a;运行查看结果 说明 该文章为作者开发学习记录&#xff0c;方便以后复习和交流主要内容为&#xff1a;…

MGIE官网体验入口 苹果多模态大语言模型AI图像编辑工具在线使用地址

MGIE是一项由苹果开源的技术&#xff0c;利用多模态大型语言模型&#xff08;MLLMs&#xff09;生成图像编辑指令&#xff0c;通过端到端训练&#xff0c;捕捉视觉想象力并执行图像处理操作&#xff0c;使图像编辑更加智能、直观。 MGIE官网体验入口https://github.com/apple/M…

Mybatis- plus 基本使用

目录 一. 引入依赖 二.定义Mapper 三.常见注解 3.1TableName 3.2.TableId 3.3TableField 3.4常见配置 一. 引入依赖 由于这个starter包含对mybatis的自动装配&#xff0c;因此完全可以替换掉Mybatis的starter。 <dependency><groupId>com.baomidou</gr…

Python: pip install -e

pip install -e . 该命令会执行当前目录下的setup.py文件,将当前项目以editable mode安装&#xff1b; # pip 文档 https://pip.pypa.io/en/stable/cli/pip_install/ # Editable Install vs. Regular Install https://pip.pypa.io/en/stable/topics/local-project-install…