《Java高并发与集合框架》第三部分在高并发场景中工作的集合

news2024/11/17 7:47:04

《Java高并发与集合框架》第三部分在高并发场景中工作的集合

  • 前言
  • 1.高并发场景中的List、Map和Set集合
    • 1.1 CopyOnWriteArrayList
    • 1.2 CopyOnWriteArrayList不支持的使用场景
    • 1.3 CopyOnWriteArrayList主要方法
    • 1.4 java.util.Collections.synchronizedList()方法的补充作用
      • 1.4.1 CopyOnWriteArrayList集合工作机制的特点
      • 1.4.2 java.utiI.CoIIections.synchronizedList()方法
    • 1.5 Map集合实现——ConcurrentHashMap
    • 1.6 高并发场景中的List、Map、Set集合说明
  • 2. 高并发场景中的Queue集合
    • 2.1 什么是阻塞队列,什么是非阻塞队列
    • 2.2 Queue集合实现——ArrayBlockingQueue

前言

高并发场景中的集合,其优先关注的问题通常不是集合的整体性能,而是工作的稳定性和在特定场景中的高性能。

1.高并发场景中的List、Map和Set集合

1.1 CopyOnWriteArrayList

Copy On Write的字面意思是写时复制。当进行指定数据的写操作时,为了不影响其他线程同时在进行的集合数据读操作,可以使用如下策略:在进行写操作前,首先复制一个数据副本,并且在数据副本中进行写操作;在副本中完成写操作后,将当前数据替换成副本数据。

很多软件在设计上都存在Copy On Write思想,被技术人员广泛熟知的是Redis中对Copy On Write思想的应用。Redis为了保证其读操作性能,在周期性进行RDB(持久化)操作时使用了CopyOn Write思想。由于RDB的操作时间主要取决于磁盘I/O性能,因此如果内存中需要进行持久化操作的数据量过大,就会产生较长的操作时间,从而影响Redis性能。改进办法是,在进行持久化操作前,先做一个当前数据的副本,并且根据副本内容进行持久化操作,从而使当前数据的状态被固定下来,并且不影响对原始数据的任何操作,如图下图所示
在这里插入图片描述


Copy On Write思想在Java中的一种具体实现是CopyOnWriteArrayList集合,该集合在进行写操作时会创建一个内存副本,并且在副本中进行相关操作,最后使用副本内存空间替换真实的内存空间。但是创建副本内存空间是有性能消耗的,特别是当CopyOnWriteArrayList集合中的数据量较大时。

因此CopyOnWriteArrayList集合适合用于读操作远远多于写操作,并且在使用时需要保证集合读操作性能的多线程场景。


CopyOnWriteArrayList集合的内部结构和工作原理
CopyOnWriteArrayList集合的主要属性如下。
在这里插入图片描述
在以上源码中,CopyOnWriteArrayList集合中只有两个关键属性。lock属性是前面已经介绍过的ReentrantLock对象,CopyOnWriteArrayList集合在高并发场景中,主要使用lock属性控制线程操作权限,从而保证集合中数据对象在多线程写操作场景中的数据正确性

CopyOnWriteArrayList集合除了直接实现了java.util.List接口,还实现了java.util.RandomAccess接口。java.util.RandomAccess接口是一种标识接口,表示实现类在随机索引位上的数据读取性能不受存储的数据规模影响,即进行数据读操作的时间复杂度始终为O(1)

1.2 CopyOnWriteArrayList不支持的使用场景

因为CopyOnWriteArrayList集合在进行数据写操作时,会依靠一个副本进行操作,所以不支持必须对原始数据进行操作的功能。例如,不支持在迭代器上进行的数据对象更改操作(使用remove()方法、set()方法和add()方法)源码如下。
在这里插入图片描述

1.3 CopyOnWriteArrayList主要方法

  1. get(int)方法
    get(int)方法主要用于从CopyOnWriteArrayList集合中获取指定索引位上的数据对象,该方法无须保证线程安全性,任何操作者、任何线程、任何时间点都可以使用该方法或类似方法获取CopyOnWriteArrayList集合中的数据对象,因为该集合中的所有写操作都在一个内存副本中进行,所以任何读操作都不会受影响。

  2. add(E)方法
    add(E)方法主要用于向CopyOnWriteArrayList集合中数组的最后一个索引位上添加一个新的数据对象,添加的数据对象可以为null
    在这里插入图片描述
    根据add(E)方法的详细描述可知,该集合通过Arrays.copyOf()方法(其内部是System.arraycopy方法)创建一个新的内存空间,用于存储副本数组,并且在副本数组中进行写操作,最后将CopyOnWriteArrayList集合中的数组引用为副本数组

  3. set(int, E)方法

1.4 java.util.Collections.synchronizedList()方法的补充作用

1.4.1 CopyOnWriteArrayList集合工作机制的特点

据CopyOnWriteArrayList集合的相关介绍,可以大致归纳出CopyOnWriteArrayList集合的特点,具体如下。

  1. 该集合适合应用于多线程并发操作场景中,如果读者使用集合的场景中不涉及多线程并发操作,那么不建议使用该集合,甚至不建议使用JUC中的任何集合,使用java.util包中符合使用场景的基本集合即可。
  2. 该集合在多线程并发操作场景中,优先关注点集中在如何保证集合的线程安全性和集合的数据读操作性能。因此,该集合以显著牺牲自身的写操作性能和内存空间的方式换取读操作性能不受影响。这个特征很好理解,在每次进行读操作前,都要创建一个内存副本,这种操作一定会对内存空间造成浪费,并且内存空间复制操作一定会造成多余的性能消耗。
  3. 该集合适合应用于多线程并发操作、多线程读操作次数远远多于写操作次数、集合中存储的数据规模不大的场景中。

1.4.2 java.utiI.CoIIections.synchronizedList()方法

Java中有没有提供一些适合在多线程场景中使用,读操作性能和写操作性能保持一定平衡性,虽然整体性能不是最好,但仍然保证线程安全的List集合呢?答案是有的。
java.util.Collections是Java为开发人员提供的一个和集合操作有关的工具包(从JDK 1.2开始提供,各版本进行了不同程度的功能调整),其中提供了一组方法,可以将java.util包下的不支持线程安全性的集合转变为支持线程安全的集合。实际上是使用Object Monitor机制将集合方法进行了封装。java.util.Collections.synchronizedList()方法的相关源码如下。

在这里插入图片描述
在使用经过java.util.Collections工具包封装的集合时,需要特别注意:原始集合的迭代器(iterator)、可拆分的迭代器(spliterator)、处理流(stream)、并行流(parallelStream)的运行都不受这种封装机制的保护,如果用户需要使用集合中的这些方法,则必须自行控制这些方法的线程安全。

1.5 Map集合实现——ConcurrentHashMap

1.6 高并发场景中的List、Map、Set集合说明

  1. CopyOnWriteArrayList:该集合已经在本章中进行了讲解,此处不再赘述。
  2. CopyOnWriteArraySet:该集合是一种Set集合,并且可以工作在高并发场景中。该集合实际上是对另一种集合的封装,不过并不是对某种Map集合的封装,而是对CopyOnWriteArrayList集合的封装,因为该集合需要满足CopyOnWrite工作要求。
  3. ConcurrentHashMap:该集合已经在本章中进行了讲解,此处不再赘述。
  4. WeakHashMap:如果读者对Java对象引用的高级知识有所了解,就会知道Java对象的引用类型一共有四种:强引用、软引用、弱引用和虚引用。而WeakHashMap集合是Java早期版本就原生提供的一种和弱引用配合使用的集合。其外在工作特性与HashMap集合的外在工作特性一致,不过在此基础上,WeakHashMap集合增加了“弱建”的概念:如果存在于WeakHashMap集合中的K-V键值对节点的Key键对象没有任何外部的强引用(或软引用),那么在GC回收时,会将该Key键对象回收。
  5. ConcurrentSkipListMap:由于篇幅有限,本书没有为读者详细介绍基于跳跃表结构的ConcurrentSkipListMap集合。出于研究集合设计的目的,跳跃表确实值得读者仔细研究并应用到日常工作中。ConcurrentSkipListMap集合结构在外在使用效果上与TreeMap集合类似(注意:这两个集合的工作场景和内在结构都不一样),两种集合都需要添加到集合中的节点支持某种排序逻辑。
  6. ConcurrentSkipListSet:该集合是一种Set集合,其内部是对ConcurrentSkipListMap集合的封装。这种封装的设计思路,类似于普通集合包中各种Set集合对Map集合的封装设计思路。

2. 高并发场景中的Queue集合

在这里插入图片描述

  1. ArrayBlockingQueue:
    这是一种内部基于数组的,在高并发场景中使用的阻塞队列,是一种有界队列。该队列的一个显著工作特点是,存储在队列中的数据对象数量有一个最大值。
  2. LinkedBlockingQueue:
    这是一种内部基于链表的,在高并发场景中使用的阻塞队列,是一种无界队列。该队列最显著的工作特点是它的内部结构是一个链表,这保证了它可以在有界队列和无界队列之间非常方便地进行转换。
  3. LinkedTransferQueue:
    这是一种内部基于链表的,可以在高并发场景中使用的阻塞队列,是一种无界队列。可以将它看成LinkedBlockingQueue队列和ConcurrentLinkedQueue队列优点的结合体,既能关注集合的读/写操作性能,又能维持队列的工作特性。在实际应用中,经常使用该队列进行线程间的消息同步操作。
  4. PriorityBlockingQueue:
    这是一种内部基于数组的,采用小顶堆结构的,可以在高并发场景中使用的阻塞队列,是一种无界队列。该队列最显著的工作特点是,队列中的数据对象按照小顶堆结构进行排序,从而保证从该队列中取出的数据对象是权值最小的数据对象。
  5. DelayQueue:
    这是一种内部依赖PriorityQueue的,采用小顶堆结构的,可以在高并发场景中使用的阻塞队列,是一种无界队列。该队列的一个显著工作特点是,队列中的数据对象除了会按照小顶堆结构进行排序外,这些数据对象还会通过实现java.util.concurrent.Delayed接口定义一个延迟时间,只有当延迟时间最小的数据对象的值都小于或等于0时(延迟时间会作为节点的权重值参与排序),该数据对象才会被外部调用者获得。

2.1 什么是阻塞队列,什么是非阻塞队列

我们知道,Queue接口是BlockingQueue接口的父级接口,前者定义了一些与队列有关的接口,后者在此基础上补充了一些接口功能,Queue接口的主要方法如下。
在这里插入图片描述
在这里插入图片描述

2.2 Queue集合实现——ArrayBlockingQueue

ArrayBlockingQueue队列是一种经常使用的线程安全的Queue集合实现,它是一种内部基于数组的,可以在高并发场景中使用的阻塞队列,也是一种容量有界的队列。该队列符合先进先出(FIFO)的工作原则,也就是说,该队列头部的数据对象是最先进入队列的,也是最先被调用者取出的数据对象;该队列尾部的数据对象是最后进入队列的,也是最后被调用者取出的数据对象。

在多线程同时读/写ArrayBlockingQueue队列中的数据对象时,该队列还支持一种公平性策略,这是一种为生产者/消费者工作模式提供的功能选项(可以将ArrayBlockingQueue队列的读取操作线程看成消费者角色,将写入操作线程看成生产者角色),如果启用了这个功能选项,那么ArrayBlockingQueue队列会分别保证多个生产者线程和多个消费者线程获取ArrayBlockingQueue队列操作权限的顺序——先请求操作的线程会先获得操作权限。ArrayBlockingQueue队列的基本继承体系如图9-2所示。
在这里插入图片描述
// TODO

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

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

相关文章

Allegro如何实现交换pin操作详细指导

Allegro如何实现交换pin操作详细指导 在做PCB设计的时候,换pin是用的较多的功能,换pin可以让线序更加的顺,方便布线。但是前提是确保网络的交换是被允许的 下面用下图为例介绍Allegro中是如何实现交换pin的 具体操作如下 选择File选择Export-Libraries

2022年终,盘点IT行业全年10大事件

白云苍狗,一眨眼,2022年就来到了尾声。这一年里,IT行业发生了不少的大事。有喜有忧,令人目不暇接,显现出IT行业风云变幻的一面。 本期,知了姐为大家整理了近一年来,IT行业发生的10件大事。 NO…

Linux下安装mysql

下载地址: https://dev.mysql.com/downloads/mysql/ 1.解压mysql 文件包,解压路径/home/mysql tar -zxvf mysql-8.0.31-linux-glibc2.12-x86_64.tar 2.编写配置 [client] #password your_password port 3306 socket /home/mysql/…

无线网络监控分析工具

多年来,网络设备已经从房间大小的机器急剧转变为小型便携式设备。随着设备尺寸发生巨大变化,将这些设备相互连接所涉及的技术也发生了巨大变化。这些剧烈变化的结果是无线网络的形成。无线网络的优势在于网络中的各种设备之间不需要物理连接。此外&#…

GoLang ~ 远程调试

前提条件 在编译go项目时,使用​​go build -gcflags "all-N -l"​​,关闭内联优化,以支持debug。 关于​​-gcflags "-N -l"​​参数的解释: 编译时,如果编译的结果需要gdb调试则使用参数​​-…

ASEMI整流桥2W10,DB107S和KBP307封装参数对比

编辑-Z ASEMI整流桥2W10,DB107S和KBP307是很常见的型号,今天就把整流桥2W10,DB107S和KBP307的封装参数对比一小,以便大家在选型时有更好的参考。 2W10参数: 型号:2W10 封装:WOB-4 最大重复峰…

Redis实现全局唯一id,实现优惠卷秒杀的下单功能

Redis实现全局唯一id public class RedisIdWorker {private StringRedisTemplate stringRedisTemplate;public RedisIdWorker(StringRedisTemplate stringRedisTemplate) {this.stringRedisTemplate stringRedisTemplate;}//开始时间戳private static final long BEGIN_TIMEST…

Postman之接口关联

一、前言 在我们做接口测试时,绝大多数测试人员都会使用 Postman 来进行测试,因为 Postman 的易用性非常好。进行单接口测的时候十分方便,但是实际项目上很多接口都会有依赖关系,这使得每次接口请求前,都要先手动获取…

JMeter操作笔记

通过这个图,我们可以看到一个简单的计算逻辑: 1. 如果有 10000 个在线用户数,同时并发度是 1%,那显然并发用户数就是 100。 2. 如果每个线程的 20TPS,显然只需要 5 个线程就够了(请注意,这里…

函数编程和Stream

在函数编程里用到了一些Lamada语法,因此要先了解一些lamada的内容,然后再了解函数编程,进一步再去了解stream 一、lamada使用语法 1.1、使用格式 lambda 表达式的语法格式如下: (parameters) -> expression 或 (parameters…

专家通过六点考证唐村《李氏族谱》:辨别家谱真伪,有这些窍门

如何辨别家谱真实性 家谱与史书、地方志都是史学界无比重视的史料文献,诸如唐村《李氏族谱》就为我们解开了明末、传统武术、太极拳等谜团,也让我们站在社会底层的角度看到了明末清初的种种变革和生活影响。但家谱的内容相比较史书与地方志而言&#xf…

DEJA_VU3D - Cesium功能集 之 091-绘制等高线(纯前端)

前言 编写这个专栏主要目的是对工作之中基于Cesium实现过的功能进行整合,有自己琢磨实现的,也有参考其他大神后整理实现的,初步算了算现在有差不多实现小130个左右的功能,后续也会不断的追加,所以暂时打算一周2-3更的样子来更新本专栏(尽可能把代码简洁一些)。博文内容…

Allegro如何实现交换functions操作详细指导

Allegro如何实现交换functions操作详细指导 在做PCB设计的时候,换function也是用的较多的功能。但是前提是确保交换是被允许的 同样下面用下图为例介绍Allegro中是如何实现交换function的 具体操作如下 选择File选择Export-Libraries

学习使用html2canvas生成渐变色背景图片

学习使用html2canvas生成渐变色背景图片全部代码html2canvas官网生成图片的下载全部代码 <!DOCTYPE html> <html><head><meta charset"utf-8"><title>生成渐变色背景图片</title> </head><style>#grad1 {width: 75…

c#入门-数字的字面量

指定类型 整数类型适应性类型 通常情况下&#xff0c;整数的字面量写出来是int类型。 如果数字足够大&#xff0c;那么会逐渐变成long&#xff0c;ulong类型 指定整数类型 或者&#xff0c;在数字后加上L&#xff08;不区分大小写&#xff0c;但一般用大写的L&#xff0c;…

Blender K帧与曲线编辑器

文章目录关键帧.三种K帧方式.自动K帧.物体属性K帧.快捷键K帧.曲线编辑器.打开曲线编辑器.曲线编辑器介绍.控制柄类型.插值模式.关键帧. 1 点击一个模型&#xff0c;即可在时间轴上看到这个模型的关键帧 2 blender的关键帧使用菱形表示 3 未选中的关键帧是灰色&#xff0c;选中…

Eyeshot 2023 预期 Eyeshot 2023 二月发布

Eyeshot 2023 预期 定价和包装 Eyeshot 2023 许可证将仅限于多平台。为了简化激活码的管理并防止平台升级/降级/切换疯狂&#xff0c;所有 Eyeshot 2023 许可证将包括 WinForms、WPF 和中立的跨平台核心。 因此&#xff0c;客户可以免费试用 WinForms、WPF 或中立的跨平台核心&…

FPGA知识汇集-源同步时序系统

02. 源同步时序系统 针对普通时钟系统存在着限制时钟频率的弊端&#xff0c;人们设计了一种新的时序系统&#xff0c;称之为源同步时序系统。它最大的优点就是大大提升了总线的速度&#xff0c;在理论上信号的传送可以不受传输延迟的影响。下面我们来看看这种源同步时钟系统的结…

Python接口测试实战3(下)- unittest测试框架

本节内容 unittest简介用例编写用例组织及运行生成测试报告 unitttest简介 参考&#xff1a;unittest官方文档 翻译版 为什么要使用unittest&#xff1f; 在编写接口自动化用例时&#xff0c;我们一般针对一个接口建立一个.py文件&#xff0c;一条测试用例封装为一个函数&…

前端性能优化(二):浏览器渲染优化

目录 一&#xff1a;浏览器渲染原理和关键渲染路径&#xff08;CRP&#xff09; 1.1.浏览器渲染过程 1.2.DOM树 1.3.CSS树 1.4.浏览器构建渲染树 二&#xff1a;回流与重绘 2.2.影响回流的操作 2.3.避免布局抖动&#xff08;layout thrashing&#xff09; 三&#xff1a…