【多线程】多线程下使用集合类

news2024/11/26 21:45:22

一.Java中线程安全的集合类

Java中提供了多种线程安全的集合类,它们可以在多线程环境下安全地被多个线程同时访问而无需外部同步。以下是一些常见的线程安全集合类:

  1. Vector: 类似于 ArrayList 的动态数组,但是所有方法都是同步的,提供了基本的线程安全保证。
  2. Hashtable: 是一个线程安全的哈希表实现,与 HashMap 类似,但所有操作都是同步的。
  3. Stack: 继承自 Vector 的线程安全栈实现。
  4. ConcurrentLinkedQueue: 使用非阻塞算法的线程安全队列实现。
  5. BlockingQueue: 这是一个接口,它有多个实现类(如 ArrayBlockingQueue, LinkedBlockingQueue 等),这些实现类提供了线程安全的队列操作。
  6. CopyOnWriteArrayList: 一个线程安全的列表,它在修改操作时复制底层数组,从而避免并发修改异常。
  7. CopyOnWriteArraySet: 基于 CopyOnWriteArrayList 的线程安全集合。
  8. ConcurrentHashMap: 提供比 Hashtable 更好的并发性能的线程安全哈希表实现。
  9. ConcurrentSkipListMap: 线程安全且数据有序的哈希表。

需要注意的是,虽然这些集合类是线程安全的,但在特定场景下可能存在性能差异。例如,Vector和Hashtable的每个操作都是通过synchronized关键字进行同步的,这可能在高并发情况下成为性能瓶颈。而其他一些类,如ConcurrentHashMap,采用了更精细的锁定机制来提高并发性能。

二.多线程下使用ArrayList

  • 给自己加锁 : 在涉及线程安全的代码中用(synchronized或者ReentrantLock)加锁
  • 使用Collections.synchronizedList包装器:Collections.synchronizedList(new ArrayList ) 给ArrayList各种操作本身不带锁.通过上述套壳之后,得到的新的对象里面的关键方法都带有锁了.
    Java 提供了一个便利的方法来创建一个同步的列表,即 Collections.synchronizedList。这个方法返回一个线程安全的列表,所有对它的直接操作都是同步的。但请注意,迭代时用户必须手动对这个列表进行同步。
    代码示例:
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;

List<Object> syncList = Collections.synchronizedList(new ArrayList<>());

public void addToList(Object item) {
    synchronized(syncList) {
        syncList.add(item);
    }
}

public Object removeFromList(int index) {
    synchronized(syncList) {
        return syncList.remove(index);
    }
}

  • 使用并发集合类:CopyOnWriteArrayList 写时拷贝,多个线程读是没有线程安全问题的 如果多个线程读这个顺序表, 没有任何线程安全问题~如果一旦有线程要修改这里的值,就会把该顺序表复制一份,修改复制表中的内容,然后修改引用的指向(原子的)
    如果性能是个问题,并且你不想手动管理同步,可以考虑使用 java.util.concurrent 包中的线程安全集合类,如 CopyOnWriteArrayList。
    代码示例:
import java.util.concurrent.CopyOnWriteArrayList;

List<Object> cowList = new CopyOnWriteArrayList<>();

public void addToList(Object item) {
    cowList.add(item);
}

public Object removeFromList(int index) {
    return cowList.remove(index);
}

三.多线程下使用队列

多线程下使用队列一般是使用阻塞队列:
Java 提供了多种阻塞队列的实现,它们可以在多线程环境下安全地传递元素。以下是一些常用的阻塞队列种类:

  1. ArrayBlockingQueue: 一个由数组支持的有界阻塞队列。
  2. LinkedBlockingQueue: 一个由链表支持的可选边界阻塞队列,其性能通常优于 ArrayBlockingQueue。
  3. PriorityBlockingQueue: 一个支持优先级排序的无界阻塞队列。
  4. DelayQueue: 一个使用优先级队列实现的无界阻塞队列,用于延迟元素的传输。
  5. SynchronousQueue: 一个不存储元素的阻塞队列,适用于传递性设计。
  6. LinkedTransferQueue: 一个由链表支持的无界阻塞队列,相对于 LinkedBlockingQueue,它提供了更高级的传输操作。TransferQueue 的应用场景是,当不想生产者过度生产消息时,TransferQueue可能非常有用,在这样的设计中,消费者的消费能力将决定生产者产生消息的速度。
  7. LinkedBlockingDeque: 一个由双向链表支持的可选边界阻塞队列,可以用作栈或队列。
  8. ConcurrentLinkedQueue: 虽然不是阻塞队列,但它是 Java 中的一个非阻塞线程安全的队列,适用于高并发场景。

这些队列提供了不同的特性和性能特点,适用于不同的应用场景。例如,如果你需要处理具有优先级的任务,可以使用 PriorityBlockingQueue。如果你需要一个不存储任何元素而是直接将生产的元素传递给消费者的队列,那么 SynchronousQueue 可能是合适的选择。

在选择阻塞队列时,需要考虑队列的特性,如是否有界、是否支持优先级、是否支持延迟处理等。此外,还需要考虑预期的使用模式,例如,是否会有多个生产者和消费者,以及它们之间的交互模式。了解这些队列的特点和适用场景,可以帮助你更好地在多线程程序中管理数据的生产和消费。

四.多线程下使用哈希表

HashMap肯定不行,是线程不安全的
HashTable 给HashMap的关键方法加锁来保证线程安全
Hashtable的每个操作都是通过synchronized关键字进行同步的,这可能在高并发情况下成为性能瓶颈.因此就引出了ConcurrentHashMap(并发HashMap)

ConcurrentHashMap的优化:

  • 1.最大的优化之处减小了锁的粒度 HashMap由数组+若干的链表 . 若是HashTable若修改两个不同的链表中的数据,也会产生锁竞争,这也相当于给this加锁了;缩小了锁的粒度,就相当于把锁给到了每一个链表,此时若再修改两个不同链表中的值,就不会产生锁冲突了 ConcurrentHashMap相比于HashTable 大大缩小了锁冲突的概率,把一把大锁,转换成多把小锁了。
    在这里插入图片描述
    此时元素1和元素2在同一链表上,如果线程A修改(增删)元素1,线程B修改元素2,那么此时是有线程安全问题的(相邻两元素并发的插入或者删除的时候,相邻两节点的next指向可能会发生改变)。如果线程A修改(增或者删)元素3,线程B修改元素4,,这个情况相当于多个线程修改不同的变量,那么此时是没有线程安全问题的。
    使用HashTable,锁冲突概率就太大了,任何两个元素的操作都会有锁冲突,即使是处在不同的链表上,这就是不用HashTable的主要原因。
    ConcurrentHashMap做法是,每个链表有各自的锁(而不是大家共用同一个锁了),具体来说,就是使用每个链表的头结点,作为锁对象(两个线程针对同一个锁对象加锁才有锁竞争,才有阻塞等待,针对不同对象,没有锁竞争)。
    此时,把锁的粒度变小了,针对12这个情况,是针对同一把锁进行加锁,会有锁竞争,会保证线程安全。针对34这个情况,是针对不同的锁进行加锁,不会有锁竞争了,没有阻塞等待,程序就会更快。
  • 2.针对读操作,不加锁,只针对写操作加锁
    读和读之间没有冲突;写和写之间有冲突,可以加锁;读和写之间没有冲突,但是很多场景下,读写之间不加锁控制,如果写操作不是原子的,那么会产生脏读,所以使用了 volatile 保证了原子性。
  • 3.充分的使用了CAS原子操作~减少了一些加锁 -比如针对哈希表元素个数的维护
  • 4.针对扩容操作的优化:
    扩容本质上是创建一个更大的数组,把旧的Hash表中的元素都给搬运到新的数组上,如果Hash表的元素本身非常多,这里的扩容操作就会消耗很长时间.
    扩容优化:HashMap的扩容操作是一把梭哈 . 在某次插入元素的操作中,整体完成扩容…而ConcurrentHashMap则是每次操作都只是搬运一部分元素~~就是在扩容的过程中,同时存在两份哈希表,一份是旧的,一份是新的.插入操作,直接往新的上插,删除操作,新的旧的都删除,查找操作新的和旧的都需要查询.
    小结:
一.Hashtable和HashMap、ConcurrentHashMap 之间的区别?
  • HashMap: 线程不安全. key 允许为 null
  • Hashtable: 线程安全,使用 synchronized 锁 Hashtable 对象, 效率较低,key 不允许为 null
  • ConcurrentHashMap: 线程安全,使用 synchronized 锁每个链表头结点, 锁冲突概率低, 充分利用
  • CAS 机制,优化了扩容方式,key 不允许为 null
二. ConcurrentHashMap在jdk1.8做了哪些优化?
  • 取消了分段锁, 直接给每个哈希桶(每个链表)分配了一个锁(就是以每个链表的头结点对象作为锁对象)。将原来 数组 + 链表 的实现方式改进成 数组 + 链表 / 红黑树 的方式,当链表较长的时候(大于等于8 个元素)就转换成红黑树。
  • PS:分段锁是 Java1.7 中采取的技术,Java1.8 中已经不再使用了,简单的说就是把若干个哈希桶分成一个"段", 针对每个段分别加锁,目的也是为了降低锁竞争的概率。当两个线程访问的数据恰好在同一个段上的时候, 才触发锁竞争。
三.ConcurrentHashMap的读是否要加锁?

读操作没有加锁,目的是为了进一步降低锁冲突的概率,为了解决脏读,保证读到刚修改的数据, 搭配了

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

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

相关文章

ThinkPhp8 框架使用 mysql find_in_set 函数

前言: 使用mysql 存储一些标签时 会使用逗号拼接的存储方法 比如 1,2,3,11 一般情况下 查询 1 可能会用到 like %1% 但这样查询的不够准确 因为11也会被查询到 如果每次都多一个逗号 1,2,3,11, 查询时 like %1,% 这样存储有点不太符合程序设计 解决方案 ----------- 官网…

Linux 5.10 Pstore 功能测试

目录 简介环境配置内核配置参考备注 简介 Pstore(Persistent store support)是用于系统发生oops或panic时&#xff0c;自动保存内核log buffer中的日志。随着功能不断完善&#xff0c;Duo S使用Linux 5.10已经支持保存console日志、ftrace消息和用户空间日志的收集&#xff0c…

【Shell语言学堂】Shell 脚本练习1

Shell 脚本练习 shell语言实战 Shell 脚本练习&#x1f4a7;CSDN划过手的泪滴t现有一个脚本可传入n个参数&#xff0c;要求在脚本中实现在终端输出第n个参数之前的所有参数(不包含第n个参数)编写一个计算bmi体质指数的脚本&#xff0c;该脚本需要用户输入身高和体重信息&#x…

登录信息失效后多次请求提示合并成一次

在通常的业务场景中经常会出现进入页面之后一次性发送好多个请求,如果登录信息失效,那就会出现很多提示 类似这种多个提示的,看起来不美观,希望改成可以把在短时间内出现相同的错误信息,只提示一次,其他的就不提示了 实现思路 通常业务中每一个请求的code都是有具体的意思,可以…

虚拟机VMware启动虚拟机刚启动有网之后没网

虚拟机VMware启动虚拟机刚启动有网之后没网 害&#xff0c;感觉这种调试的事情是真的浪费时间 如题&#xff0c;对于这种情况&#xff0c;一句话&#xff0c;就是你本地的DHCP虚拟机服务以及NAT网络服务没启动 本机windowR,输入services.msc 进入服务 然后 喏&#xff0c;…

【MATLAB源码-第182期】基于matlab的QPSK调制解调系统频偏估计及补偿算法仿真,对比补偿前后的星座图误码率。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 在通信系统中&#xff0c;频率偏移是一种常见的问题&#xff0c;它会导致接收到的信号频率与发送信号的频率不完全匹配&#xff0c;进而影响通信质量。在调制技术中&#xff0c;QPSK&#xff08;Quadrature Phase Shift Keyi…

LowCodeEngine基础教程

一、技术介绍 1、应用场景 LowCodeEngine支持一下四种通用场景&#xff1a;中后台页面、移动端页面、流程、可视化报表。 2、低代码的特点 3、低代码在阿里巴巴实践 4、开发痛点 中后台页面中&#xff0c;对于页面的视觉冲击、视觉炫酷要求并不是很敏感&#xff0c;更多的是…

【Linux进阶之路】ARP欺骗实验

正文 话不多说&#xff0c;直接干&#xff01; 首先我们需要准备一下环境&#xff0c;先配置VMARE&#xff0c;然后下载KALI的虚拟机。 详细的安装教程视频&#xff1a;点击跳转&#xff0c;下载KALI可能要半个小时&#xff0c;中间可以看个剧玩个游戏缓一缓。 配置好之后&am…

K8s学习八(配置与存储_配置)

配置与存储 配置管理 ConfigMap ConfigMap的创建 一般用于去存储 Pod 中应用所需的一些配置信息&#xff0c;或者环境变量&#xff0c;将配置于 Pod 分开&#xff0c;避免应为修改配置导致还需要重新构建 镜像与容器。configmap缩写为cmkubectl create cm -h来查看创建命令…

java+mysql图书管理系统制作教程v1.0.0完整版

本人QQ&#xff1a;2711138299&#xff0c;需要源码的可以加我,附带数据库备份文件&#xff0c;以及建立数据库表 下面是我写在有道云笔记里面的教程&#xff0c;由于复制粘贴后&#xff0c;代码都混乱在一起了&#xff0c;不建议大家观看&#xff0c;所以想看详细教程的也可以…

拥有自己的云环境-域名及备案

序 唠叨两句 之前的文章&#xff0c;讲了如何购买一台云服务器&#xff0c;然后购买之后&#xff0c;如何操作云服务器。当买完云服务器之后&#xff0c;我们就可以使用云服务器提供的公网ip&#xff0c;访问到我们的服务器上。但是&#xff0c;这样怎么能体现我们一个老程序…

Hybrid混合开发 和 Android平台JSBridge的原理

书接上篇&#xff1a;移动端研发技术的进化历程 纯原生开发主要面临动态化和开发成本两个问题&#xff0c;而针对这两个问题&#xff0c;诞生了一些跨平台的动态化框架。 针对原生开发面临的问题&#xff0c;业界一直都在努力寻找好的解决方案&#xff0c;而时至今日&#xf…

【深度学习】图像风格混合——StyleGAN原理解析

1、前言 上一篇&#xff0c;我们讲了PGGAN的模型原理&#xff0c;本章我们就来讲解一下StyleGAN&#xff0c;这个模型能够自由控制图像的风格&#xff0c;细节变化等等&#xff0c;生成用户想要的图像&#xff0c;甚至从某种程度上说&#xff0c;其可以实现AI换脸。 PS&#…

[StartingPoint][Tier1]Pennyworth

Important Jenkins是一个用于自动化构建、测试和部署软件项目的开源持续集成和持续部署&#xff08;CI/CD&#xff09;工具。它允许开发团队自动执行和监控在软件开发过程中的重复性任务&#xff0c;例如构建代码、运行测试、部署应用程序等。Jenkins提供了一个易于使用的Web界…

ST表的解释

介绍 ST表&#xff1a;一种用于高效处理区间查询的数据结构。它可以在O(1)的时间复杂度内回答某一区间的最值查询&#xff08;最小值、最大值等&#xff09;。ST表使用动态规划的思想&#xff0c;通过预处理的方式来快速计算出各个区间的最值。 st算法的主要思想就是将所求的…

为什么 MySQL 采用 B+ 树作为索引?

资料来源 : 小林coding 小林官方网站 : 小林coding (xiaolincoding.com) 「为什么 MySQL 采用 B 树作为索引&#xff1f;」这句话&#xff0c;是不是在面试时经常出现。 要解释这个问题&#xff0c;其实不单单要从数据结构的角度出发&#xff0c;还要考虑磁盘 I/O 操作次数&am…

【操作系统】python实现银行家算法

银行家算法是最具有代表性的避免死锁的算法。 1、算法原理 银行家算法&#xff1a;当一个新进程进入系统时&#xff0c;该进程必须申明在运行过程中所需要的每种资源的最大数目&#xff0c;且该数目不能超过系统拥有的资源总量。当进程请求某组资源时&#xff0c;系统必须先确…

Enzo Life Sciences--17β-Estradiol high sensitivity ELISA kit

高灵敏ELISA试剂盒&#xff0c;可检测到低至14 pg/ml的17β-雌二醇 雌二醇(estradiol) 是由卵巢内卵泡的颗粒细胞分泌的类固醇激素&#xff0c;是主要的雌激素&#xff0c;负责调节女性特征、附属性器官的成熟和月经-排卵周期&#xff0c;促进乳腺导管系统的产生&#xff0c;有…

机器人客户端如何配置同步消息至多个群中

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。 前言 由于微信群的人数&#xff0c;最多是500人&#xff0c;如果有人的业务做的大&#xff0c;可能会同步创建好多个群&#xff0c;但是资料的不想多个群一起发&#xff0c;发给某个群&a…

产品经理和项目经理的区别

1. 前言 本文深入探讨了产品经理与项目经理在职责、关注点以及所需技能方面的显著区别。产品经理主要负责产品的规划、设计和市场定位,强调对用户需求的深刻理解和产品创新的推动;而项目经理则侧重于项目的执行、进度控制和资源管理,确保项目按时、按质、按预算完成。两者在…