当前位置: 首页 > news >正文

聊聊并发编程——并发容器和阻塞队列

目录

一.ConcurrentHashMap

1.为什么要使用ConcurrentHashMap?

2.ConcurrentHashMap的类图

3.ConcurrentHashMap的结构图

二.阻塞队列

Java中的7个阻塞队列

ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列。

LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列。可以指定容量也可以无界。

PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。

DelayQueue:一个使用优先级队列实现的无界阻塞队列。 用于按照指定延迟时间对元素进行排序的阻塞队列。

SynchronousQueue:一个不存储元素的阻塞队列。常用于线程间的手递手传递。

LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。


一.ConcurrentHashMap

1.为什么要使用ConcurrentHashMap?
  • 不安全的HashMap

    Java 中的 HashMap 是非线程安全的,这意味着如果多个线程同时访问和修改同一个 HashMap 实例,可能会导致不一致的结果或抛出异常。以下是一个示例代码,展示了 HashMap 的线程不安全行为:

public static void main(String[] args) {// 创建一个 HashMapMap<Integer, String> map = new HashMap<>();// 创建一个线程池ExecutorService executorService = Executors.newFixedThreadPool(2);// 向 HashMap 中添加键值对的任务Runnable task = () -> {for (int i = 0; i < 1000; i++) {map.put(i, "Value " + i);}};// 启动两个线程同时执行添加任务executorService.submit(task);executorService.submit(task);// 等待线程池执行完毕executorService.shutdown();// 等待一段时间以确保线程池完成try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}// 输出 HashMap 的大小System.out.println("HashMap size: " + map.size());}

在上述示例中,我们创建了一个包含两个线程的线程池,并让它们同时向同一个 HashMap 实例中添加键值对。由于 HashMap 不是线程安全的,这样的并发写入操作可能导致不一致的结果。在某些情况下,可能会抛出 ConcurrentModificationException 异常。

  • 效率低下的HashTable

    HashTable容器使用synchronized来保证线程安全,但在线程竞争激烈的情况下HashTable 的效率非常低下。因为当一个线程访问HashTable的同步方法,其他线程也访问HashTable的同 步方法时,会进入阻塞或轮询状态。如线程1使用put进行元素添加,线程2不但不能使用put方 法添加元素,也不能使用get方法来获取元素,所以竞争越激烈效率越低。

  • ConcurrentHashMap的锁分段技术可有效提升并发访问率

    HashTable容器在竞争激烈的并发环境下表现出效率低下的原因是所有访问HashTable的 线程都必须竞争同一把锁。

    ConcurrentHashMap所使用的锁分段技术。首先将数据分成一段一段地存 储,然后给每一段数据配一把锁,当一个线程占用锁访问其中一个段数据的时候,其他段的数据也能被其他线程访问。

2.ConcurrentHashMap的类图

3.ConcurrentHashMap的结构图

二.阻塞队列

阻塞队列(BlockingQueue)是一个支持两个附加操作的队列。这两个附加的操作支持阻塞的插入和移除方法。

  • 支持阻塞的插入方法:当队列满时,会阻塞插入元素的线程,直到队列不满。

  • 支持阻塞的移除方法:当队列为空时,获取元素的线程会等待队列变为非空。

阻塞队列常用于生产者和消费者场景。生产者就是添加元素的线程,消费者就是获取元素的线程,阻塞队列就是生产者存放元素、消费者获取元素的容器。插入和移除操作的4中处理方式:

方法/处理方式抛出异常返回特殊值一直阻塞超时退出
插入方法add(e)offer(e)put(e)offer(e,time,unit)
移除方法remove()poll()take()poll(time,unit)
检查方法element()peek()不可用不可用
  • 抛出异常:当队列满了,再插入元素时,会抛出IllegalStateException(“Queue full”)异常。当队列为空,再获取元素,会抛出NoSuchElementException异常。

  • 返回特殊值:当队列插入元素时,会返回元素是否插入成功,成功返回true。如果是移除方法,则是从队列去除元素,如果不存在则返回null。

  • 一直阻塞:当队列满时,往队列put元素,队列会一直阻塞添加元素的线程,知道队列可用或者响应中断退出。当队列为空时,如果从队列中take元素,队列会阻塞获取元素的线程,知道队列不为空。

  • 超时退出:当队列满时,如果插入元素,队列会阻塞插入元素的线程一段时间,超过了指定时间,线程就会退出。

Java中的7个阻塞队列

如果是无界阻塞队列,队列不可能会出现满的情况,所以使用put或offer方法永 远不会被阻塞,而且使用offer方法时,该方法永远返回true。

  • ArrayBlockingQueue:一个由数组结构组成的有界阻塞队列。
    public class ArrayBlockingQueueExample {public static void main(String[] args) throws InterruptedException {ArrayBlockingQueue<Integer> arrayBlockingQueue = new ArrayBlockingQueue(5);
    ​// 生产者Thread produce = new Thread(()->{try {for (int i = 0; i < 10; i++) {arrayBlockingQueue.put(i);System.out.println("produced:" + i);}} catch (InterruptedException e) {e.printStackTrace();}});
    ​// 消费者Thread consume = new Thread(()->{try {while (true) {int i = arrayBlockingQueue.take();System.out.println("consumed" + i);}} catch (InterruptedException e) {e.printStackTrace();}});
    ​produce.start();consume.start();
    ​Thread.sleep(2000);produce.interrupt();consume.interrupt();}
    }

  • LinkedBlockingQueue:一个由链表结构组成的有界阻塞队列。可以指定容量也可以无界。
    public class LinkedBlockingQueueExample {public static void main(String[] args) throws InterruptedException {LinkedBlockingQueue<Integer> queue = new LinkedBlockingQueue(5);
    ​// 同上,创建生产者和消费者线程并启动
    ​// 主线程等待,中断生产者和消费者Thread.sleep(2000);produce.interrupt();consume.interrupt();}
    }
  • PriorityBlockingQueue:一个支持优先级排序的无界阻塞队列。
    public class PriorityBlockingQueueExample {public static void main(String[] args) throws InterruptedException {PriorityBlockingQueue<Integer> queue = new PriorityBlockingQueue<>();
    ​// 同上,创建生产者和消费者线程并启动
    ​// 主线程等待,中断生产者和消费者Thread.sleep(2000);produce.interrupt();consume.interrupt();}
    }
  • DelayQueue:一个使用优先级队列实现的无界阻塞队列。 用于按照指定延迟时间对元素进行排序的阻塞队列。
    public class DelayQueueExample {public static void main(String[] args) throws InterruptedException {DelayQueue<DelayedElement > queue = new DelayQueue<DelayedElement >();
    ​// 创建消费者线程Thread consume = new Thread(() ->{try {while (true) {DelayedElement element = queue.take();System.out.println("consume:" + element.getValue());}} catch (InterruptedException e) {e.printStackTrace();}});consume.start();
    ​// 生产者添加元素queue.put(new DelayedElement("value 5", 1, TimeUnit.SECONDS));queue.put(new DelayedElement("value 4", 2, TimeUnit.SECONDS));queue.put(new DelayedElement("value 3", 3, TimeUnit.SECONDS));queue.put(new DelayedElement("value 2", 4, TimeUnit.SECONDS));queue.put(new DelayedElement("value 1", 5, TimeUnit.SECONDS));
    ​Thread.sleep(10000);
    ​consume.interrupt();}
    ​static class DelayedElement implements Delayed {private String value;private long delayTime;
    ​public String getValue() {return value;}
    ​public DelayedElement(String value, long delayTime, TimeUnit timeUnit) {this.value = value;this.delayTime = System.currentTimeMillis() + timeUnit.toMillis(delayTime);}
    ​@Overridepublic long getDelay(TimeUnit unit) {return delayTime - System.currentTimeMillis();}
    ​@Overridepublic int compareTo(Delayed o) {return Long.compare(this.delayTime, ((DelayedElement) o).delayTime);}}
    }
  • SynchronousQueue:一个不存储元素的阻塞队列。常用于线程间的手递手传递。
    public class SynchronousQueueExample {public static void main(String[] args) throws InterruptedException {SynchronousQueue<Integer> queue = new SynchronousQueue<>();// 同上,创建生产者和消费者线程并启动
    ​// 主线程等待,中断生产者和消费者Thread.sleep(2000);produce.interrupt();consume.interrupt();}
    }   
  • LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。

    public class LinkedTransferQueueExample {public static void main(String[] args) throws InterruptedException {LinkedTransferQueue<Integer> queue = new LinkedTransferQueue<>();
    ​// 同上,创建生产者和消费者线程并启动
    ​// 主线程等待,中断生产者和消费者Thread.sleep(2000);produce.interrupt();consume.interrupt();}
    }
  • LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。
    public class LinkedBlockingDequeExample {public static void main(String[] args) throws InterruptedException {LinkedBlockingDeque<Integer> deque = new LinkedBlockingDeque<>();
    ​// 同上,创建生产者和消费者线程并启动
    ​// 主线程等待,中断生产者和消费者Thread.sleep(2000);produce.interrupt();consume.interrupt();}
    }

相关文章:

聊聊并发编程——并发容器和阻塞队列

目录 一.ConcurrentHashMap 1.为什么要使用ConcurrentHashMap&#xff1f; 2.ConcurrentHashMap的类图 3.ConcurrentHashMap的结构图 二.阻塞队列 Java中的7个阻塞队列 ArrayBlockingQueue&#xff1a;一个由数组结构组成的有界阻塞队列。 LinkedBlockingQueue&#xf…...

我庄严承诺终生不去承德旅游

虽然人微言轻&#xff0c;但也要尽一份力。 在此&#xff0c;我庄严承诺&#xff1a; 如果承德相关机构不返还那名"灵活就业人员"105.82万元的财产&#xff0c;并进行公开道歉。 我将终生不去承德旅游&#xff0c; 我将终生不买承德出产的任何产品。 我还将劝诫我…...

【python】python实现杨辉三角的三种方法

文章目录 1.杨辉三角介绍&#xff1a;2.方法一&#xff1a;迭代3.方法二&#xff1a;生成器4.方法三&#xff1a;递归 1.杨辉三角介绍&#xff1a; 杨辉三角是一种数学图形&#xff0c;由数字排列成类似三角形的形状。它的每个数值等于它上方两个数值之和。这个三角形的形状可以…...

GitHub 基本操作

最近要发展一下自己的 github 账号了&#xff0c;把以前的项目代码规整规整上传上去&#xff0c;这里总结了一些经验&#xff0c;经过数次实践之后&#xff0c;已解决几乎所有基本操作中的bug&#xff0c;根据下面的操作步骤来&#xff0c;绝对没错了。&#xff08;若有其他问题…...

Docker和Docker compose的安装使用指南

一&#xff0c;环境准备 Docker运行需要依赖jdk&#xff0c;所以需要先安装一下jdk yum install -y java-1.8.0-openjdk.x86_64 二&#xff0c;Docker安装和验证 1&#xff0c;安装依赖工具 yum install -y yum-utils 2&#xff0c;设置远程仓库 yum-config-manager --add-r…...

51单片机控制电动机正反转,PWM调速,记录转动圈数。

今天的实验需要用到的材料有&#xff1a;51单片机最小系统&#xff0c;4X4的矩阵键盘&#xff0c;DC直流6V-12V带编码器电机&#xff0c;L298N模块&#xff0c;一个led小灯。下面把产品截图展示一下&#xff1a; 单片机就不展示了&#xff0c;都一样&#xff0c;下面是接线图&a…...

JAVA学习(方法的定义和调用)

一、方法的定义和调用 1、关键词&#xff1a;static表示静态方法&#xff0c;如没有返回值使用void&#xff0c;方法名前使用类型&#xff0c;例如int、float等&#xff1b; /*** 测试方法的定义和调用*/public class TestMethod {public static void main(String[] args) {a…...

Linux(CentOS/Ubuntu)——安装nginx

如果确定你的系统是基于CentOS或RHEL&#xff0c;可以使用以下命令&#xff1a; ①、安装库文件 #安装gcc yum install gcc-c#安装PCRE pcre-devel yum install -y pcre pcre-devel#安装zlib yum install -y zlib zlib-devel#安装Open SSL yum install -y openssl openssl-de…...

26962-2011 高频电磁场综合水处理器技术条件

声明 本文是学习GB-T 26962-2011 高频电磁场综合水处理器技术条件. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准规定了高频电磁场综合水处理器(以下简称处理器)的术语和定义、分类和型号、结构型式、 要求及检验、标志、包装和贮运…...

图扑软件受邀亮相 IOTE 2023 国际物联网展

IOTE 2023 国际物联网展&#xff0c;作为全球物联网领域的盛会&#xff0c;于 9 月 20 日 - 22 日在中国深圳拉开帷幕。本届展会以“IoT构建数字经济底座”为主题&#xff0c;由深圳市物联网产业协会主办&#xff0c;打造当前物联网最新科技大秀。促进物联网与各行业深度融合&a…...

C语言文件操作与管理

一、为什么使用文件 在我们前面练习使用结构体时&#xff0c;写通讯录的程序&#xff0c;当通讯录运行起来的时候&#xff0c;可以给通讯录中增加、删除数据&#xff0c;此时数据是存放在内存中&#xff0c;当程序退出的时候&#xff0c;通讯录中的数据自然就不存在了&#xff…...

蓝桥等考Python组别八级005

第一部分&#xff1a;选择题 1、Python L8 &#xff08;15分&#xff09; 运行下面程序&#xff0c;输出的结果是&#xff08; &#xff09;。 i 1 while i < 4: print(i, end ) i 1 1 2 30 1 2 31 2 3 40 1 2 3 4 正确答案&#xff1a;C 2、Python L8 &#…...

JUnit介绍

JUnit是用于编写和运行可重复的自动化测试的开源测试框架&#xff0c; 这样可以保证我们的代码按预期工作。JUnit可广泛用于工业和作为支架(从命令行)或IDE(如Eclipse)内单独的Java程序。 JUnit提供&#xff1a; 断言测试预期结果。 测试功能共享通用的测试数据。 测试套件轻…...

(高阶) Redis 7 第16讲 预热/雪崩/击穿/穿透 缓存篇

面试题 什么是缓存预热/雪崩/击穿/穿透如何做缓存预热如何避免或减少缓存雪崩穿透和击穿的区别?穿透和击穿的解决方案出现缓存不一致时,有哪些修补方案缓存预热 理论 将需要的数据提前加载到缓存中,不需要用户使用的过程中进行数据回写。(比如秒杀活动数据等) 方案 1.…...

(三) gitblit管理员手册

(一)gitblit安装教程 (二) gitblit用户使用教程 (三) gitblit管理员手册 目录 权限管理创建仓库时创建用户普通用户 管理员用户访问限制和访问权限仓库创建权限分配 Teams普通组管理员组 参考资料 权限管理 创建仓库时 选择指定的人员查看,克隆,推送 不允许fork 对应Anonymo…...

ESKF算法融合GNSS与IMU信息,航向角的偏差是如何逐渐影响到重力加速度g以及位置偏差的 CSDN gpt

1##############################ESKF算法融合GNSS与IMU信息,航向角的偏差是如何逐渐影响到重力加速度g以及位置偏差的 CSDN gpt 航向角的偏差会逐渐影响重力加速度和位置偏差。首先&#xff0c;航向角的偏差会影响重力加速度的测量值。在ESKF算法中&#xff0c;通过将IMU测…...

Java初始化大量数据到Neo4j中(二)

接Java初始化大量数据到Neo4j中(一)继续探索&#xff0c;之前用create命令导入大量数据发现太过耗时&#xff0c;查阅资料说大量数据初始化到Neo4j需要使用neo4j-admin import 业务数据说明可以参加Java初始化大量数据到Neo4j中(一)&#xff0c;这里主要是将处理好的节点数据和…...

flink1.17安装

Flink1.17安装 官网地址&#xff1a; https://nightlies.apache.org/flink/flink-docs-release-1.17/zh//docs/try-flink/local_installation/ 安装jdk11 ps&#xff1a;只能安装openjdk11&#xff0c;昨天安装的oracle jdk17&#xff0c;结果怎么也运行不起来。 sudo apt …...

SLAM从入门到精通(gmapping建图)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 前面我们介绍了hector slam建图。相对而言&#xff0c;hector slam建图对数据的要求比较低&#xff0c;只需要lidar数据就可以建图了。但是hector …...

中国312个历史文化名镇及景区空间点位数据集

一部中华史&#xff0c;既是人类创造丰富物质财富的奋头史&#xff0c;又是与自然共生共存的和谐史不仅留存下悠久丰富的人文思想和情怀&#xff0c;还在各处镌刻下可流传的生活场景&#xff0c;历史文化名镇(以下简称:名镇)就是这样真实的历史画卷。“镇”是一方的政治文化中心…...

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

React 第五十五节 Router 中 useAsyncError的使用详解

前言 useAsyncError 是 React Router v6.4 引入的一个钩子&#xff0c;用于处理异步操作&#xff08;如数据加载&#xff09;中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误&#xff1a;捕获在 loader 或 action 中发生的异步错误替…...

python打卡day49

知识点回顾&#xff1a; 通道注意力模块复习空间注意力模块CBAM的定义 作业&#xff1a;尝试对今天的模型检查参数数目&#xff0c;并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:

在 HarmonyOS 应用开发中&#xff0c;手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力&#xff0c;既支持点击、长按、拖拽等基础单一手势的精细控制&#xff0c;也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档&#xff0c…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容

基于 ​UniApp + WebSocket​实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配​微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放

简介 前面两期文章我们介绍了I2S的读取和写入&#xff0c;一个是通过INMP441麦克风模块采集音频&#xff0c;一个是通过PCM5102A模块播放音频&#xff0c;那如果我们将两者结合起来&#xff0c;将麦克风采集到的音频通过PCM5102A播放&#xff0c;是不是就可以做一个扩音器了呢…...

爬虫基础学习day2

# 爬虫设计领域 工商&#xff1a;企查查、天眼查短视频&#xff1a;抖音、快手、西瓜 ---> 飞瓜电商&#xff1a;京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空&#xff1a;抓取所有航空公司价格 ---> 去哪儿自媒体&#xff1a;采集自媒体数据进…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建

华为云FlexusDeepSeek征文&#xff5c;DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色&#xff0c;华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型&#xff0c;能助力我们轻松驾驭 DeepSeek-V3/R1&#xff0c;本文中将分享如何…...