【JavaSE】多线程之安全使用容器

不出意外这是多线程的最后一篇文章,主要介绍的是面试中比较常考的一个点——多线程下使用容器,我们开始吧~

我们知道,在单线程环境下ArrayList、HashMap等容器使用起来非常方便,但在多线程环境中,如果多个线程同时对容器进行修改,就可能导致数据不一致、数组越界甚至死循环等问题

那么在多线程环境下我们该如何安全地使用这些容器呢?

1. 多线程下使用ArrayList

首先最直接也最简单的方式:加锁

List<Integer>list=newArrayList<>();synchronized(list){list.add();}

这样写显然是可行的,也很灵活,但是对代码的侵入性强、且很容易出错(一旦出错年终奖就没了,,)

因此在实际开发过程中,更常见的做法是使用Java提供的线程安全容器,对并发控制进行统一封装(尽量把坑留给框架,而不是自己)

Collections.synchronizedList会返回一个线程安全的List,其内部通过在关键方法上加上synchronized来保证线程安全

虽然在一定程度上保证了线程安全,但是由于所有操作共用一把锁,并发度低,在读多写少场景下性能较一般,比较适合低并发场景

除了Collections.synchronizedList,Java还提供了另一种思路的线程安全list——CopyOnWriteArrayList

从名字就能看出来,它采用的是一种非常经典的并发设计思想:写时拷贝

写时拷贝的核心思路是:

  • 读操作不加锁
  • 写操作时先拷贝一份底层数组
  • 在新数组上完成修改
  • 最后一次性替换引用

好处很明显,实现了读写分离,写操作不会影响正在进行的读操作,读操作不加锁不会阻塞,并发性能很高;写操作内部使用ReentrantLock保证线程安全

同样它也存在问题,写操作时需要拷贝数组,内存开销较大;如果list本身很大或者写操作频繁,性能会明显下降;多个线程同时写入写操作仍会互相竞争锁

对比一下

方案并发度侵入性适用场景
自行加锁临时方案
synchronizedList低并发
CopyOnWriteArrayList高(读)读多写少

2. 多线程环境下使用队列

在多线程环境中,队列往往承担着线程协作的角色,例如经典的生产者-消费者模型

Java 在 java.util.concurrent 包中提供了一组 阻塞队列(BlockingQueue) 的实现,用于简化这类并发场景

阻塞队列的核心特性是,队列为空时take()阻塞,队列已满时put()阻塞,以此避免频繁的轮询和手动加锁

2.1 常见的BlockingQueue实现

  1. ArrayBlockingQueue:基于数组实现,容量固定,内存连续,结构简单
  2. LinkedBlockingQueue:基于链表实现,可以指定容量,吞吐量高(线程池中默认使用的就是这种队列实现)
  3. PriorityBlockingQueue:基于堆实现,支持元素优先级,出队顺序由优先级决定,而不是FIFO,适用于任务有明显优先级区分的场景
  4. TransferQueue:支持直接把元素交给消费者,如果没有消费者才会进入队列,更强调线程之间的“交接”,使用场景相对较少,但在高并发任务调用中性能表现优秀

3. 多线程环境下使用Map

和 ArrayList 类似,HashMap 在单线程环境下使用非常方便,但在多线程环境中却是典型的线程不安全容器

如果多个线程同时对HashMap进行put/resize等操作,可能会导致数据覆盖、链表结构被破坏、JDK7中可能出现死循环等

3.1 HashTable

HashTable是Java早期提供的线程安全Map,其实现方法也很直接:给几乎所有public方法加上了synchronized
这确实保证了线程安全,但问题同样明显,所有操作共用一把锁、并发度较低、在高并发场景下性能较差

因此,HashTable基本上只存在于学校教材中,实际开发中很少使用

3.2 ConcurrentHashMap

并发环境下的首选!!

它的设计目标非常明确:在保证线程安全的前提下,尽可能提高并发访问性能

为此,它主要做了三方面的优化:

① 细化锁粒度,从“锁整张表”到“锁单个桶”

JDK8中,写操作只锁当前桶(链表或红黑树),不同桶上的操作可以并发进行

这样一来只有在操作同一个桶时线程才可能发生阻塞,并发性能大幅提升

②原子操作维护size

Q: 为什么size在并发下这么难?
A: 多个线程同时size++,读size的线程可能看到中间状态,如果给size加全局锁,每次put/remove都要竞争,性能急剧下降

ConcurrentHashMap内部不是使用一个size,而是多个计数单元,类似

baseCount// 基础计数counterCells[]// 多个计数槽

可以理解为使用多个小本子记账,而不是所有人挤在一本账上

写操作时尽量“就近记账”,通过原子操作(CAS)对计数进行更新,在并发冲突较大时,将计数分散到多个计数单元中,不同线程更新不同计数单元,从而减少竞争

在调用size()时,会将各个计数单元的值进行累加,得到当前Map的元素数量。由于统计过程中可能存在并发写入,size()返回的是一个瞬时近似值,但在绝大多数业务场景下是可以接收的

这样设计在避免全局锁的同时,显著提升了高并发下的整体性能

③渐进式rehash

扩容是Map中开销最大的操作之一,如果扩容时一次性创建新数组将所有元素整体搬迁,那么在高并发场景下性能会非常糟糕

ConcurrentHashMap的做法是,新表和旧表同时存在,扩容过程被“拆散”到后续的多次操作中完成

具体表现为:每次put/get/remove时,顺带迁移一小部分旧数据,直到所有桶都完成迁移(蚂蚁搬家,一点一点搬)

这种渐进式扩容的方式,有效避免了长时间阻塞

综上上上所述,ConcurrentHashMap的优势主要在于锁粒度小、并发度高、针对热点操作做了大量优化、在高并发场景下性能稳定可靠

因此在多线程环境中,除非有非常明确的理由,否则应该优先选择ConcurrentHashMap,而不是HashMap或者HashTable

完结撒花★,°:.☆( ̄▽ ̄)/$:.°★

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

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

相关文章

Thinkphp的基于微服务教材征订系统(编号:

目录基于ThinkPHP的微服务教材征订系统核心功能与服务拆分技术实现与优化应用价值与扩展性项目开发技术介绍PHP核心代码部分展示系统结论源码获取/同行可拿货,招校园代理基于ThinkPHP的微服务教材征订系统 该系统采用ThinkPHP框架结合微服务架构设计&#xff0c;旨在实现教材征…

基于SpringBoot+Vue的IT交流和分享平台管理系统设计与实现【Java+MySQL+MyBatis完整源码】

摘要 随着互联网技术的快速发展&#xff0c;IT技术交流与知识分享的需求日益增长。传统的技术论坛和社交媒体平台虽然提供了基础的交流功能&#xff0c;但在专业性、系统性和用户体验方面仍有较大提升空间。尤其是在技术问答、资源共享和项目管理等方面&#xff0c;缺乏高效的整…

【JavaSE】文件基础与File类

在日常开发中&#xff0c;我们几乎每天都在和“文件”打交道&#xff1a;读取配置文件、写日志、上传下载文件…… 但很多时候&#xff0c;我们对“文件”的理解其实是比较模糊的&#xff0c;这篇文章我们将从文件的基本概念出发&#xff0c;重新了解一下文件~1. 文件基础 1.1 …

SpringBoot+Vue “衣依”服装销售平台平台完整项目源码+SQL脚本+接口文档【Java Web毕设】

摘要 随着互联网技术的快速发展&#xff0c;电子商务平台已成为现代商业的重要组成部分。服装行业作为传统零售业的代表&#xff0c;亟需通过数字化转型提升竞争力。“衣依”服装销售平台基于SpringBoot和Vue技术栈开发&#xff0c;旨在为用户提供便捷的在线购物体验。该平台整…

Thinkphp的农贸市场摊位 夜市摊位租赁系统设计与实现

目录摘要关键词项目开发技术介绍PHP核心代码部分展示系统结论源码获取/同行可拿货,招校园代理摘要 农贸市场与夜市摊位租赁系统基于ThinkPHP框架开发&#xff0c;旨在解决传统摊位管理中效率低、信息不透明等问题。系统采用B/S架构&#xff0c;结合MySQL数据库&#xff0c;实现…

Claude Code 永动机:ralph-loop 无限循环迭代插件详解(安装 / 原理 / 最佳实践 / 避坑)

Claude Code 永动机&#xff1a;ralph-loop 无限循环迭代插件详解&#xff08;安装 / 原理 / 最佳实践 / 避坑&#xff09; Claude Code 插件 ralph-loop 全解析&#xff1a;Stop Hook 无限迭代、completion-promise 退出条件与最佳实践ralph-loop 使用指南&#xff1a;让 Cla…

Java SpringBoot+Vue3+MyBatis 学科竞赛管理系统源码|前后端分离+MySQL数据库

摘要 随着信息技术的快速发展&#xff0c;学科竞赛作为高校人才培养的重要环节&#xff0c;其管理效率与信息化水平直接影响竞赛的公平性和参与度。传统的学科竞赛管理多依赖人工操作&#xff0c;存在报名流程繁琐、数据统计滞后、信息共享困难等问题。为解决这些问题&#xff…

Thinkphp的吉他谱分享平台的设计与实现

目录研究背景与意义系统设计目标技术实现要点创新与特色应用价值项目开发技术介绍PHP核心代码部分展示系统结论源码获取/同行可拿货,招校园代理研究背景与意义 随着音乐爱好者的增多&#xff0c;吉他谱共享需求日益增长。传统分享方式效率低、资源分散&#xff0c;亟需一个专业…

Java SpringBoot+Vue3+MyBatis 墙绘产品展示交易平台系统源码|前后端分离+MySQL数据库

摘要 随着数字化技术的快速发展&#xff0c;传统墙绘行业逐渐向线上平台转型&#xff0c;以满足消费者对个性化艺术品的需求。墙绘作为一种独特的装饰艺术形式&#xff0c;具有高度的定制化和艺术价值&#xff0c;但在传统交易模式下&#xff0c;供需双方的信息不对称问题显著&…

Thinkphp的基于协同过滤算法的动漫推荐系统

目录基于协同过滤算法的动漫推荐系统&#xff08;ThinkPHP实现&#xff09;项目开发技术介绍PHP核心代码部分展示系统结论源码获取/同行可拿货,招校园代理基于协同过滤算法的动漫推荐系统&#xff08;ThinkPHP实现&#xff09; 该系统采用ThinkPHP框架结合协同过滤算法&#x…

前后端分离IT交流和分享平台系统|SpringBoot+Vue+MyBatis+MySQL完整源码+部署教程

摘要 随着互联网技术的快速发展&#xff0c;传统的前后端耦合架构逐渐暴露出开发效率低、维护成本高、扩展性差等问题。前后端分离架构因其模块化、灵活性高和协作效率高等优势&#xff0c;成为现代Web开发的主流模式。在此背景下&#xff0c;设计并实现一个基于前后端分离的IT…

SpringBoot + Aviator + 规则中心:轻量级表达式引擎实现营销优惠动态计算

电商大促活动时&#xff0c;营销规则复杂多变&#xff0c;今天满300减50&#xff0c;明天买2送1&#xff0c;后天又变成阶梯式折扣&#xff1f;每次改规则都得改代码、重新发布&#xff0c;简直是开发人员的噩梦&#xff01;今天就来聊聊如何用SpringBoot Aviator表达式引擎&a…

Thinkphp的基于协同过滤算法的音乐推荐系统

目录基于协同过滤算法的音乐推荐系统&#xff08;ThinkPHP实现&#xff09;项目开发技术介绍PHP核心代码部分展示系统结论源码获取/同行可拿货,招校园代理基于协同过滤算法的音乐推荐系统&#xff08;ThinkPHP实现&#xff09; 音乐推荐系统通过分析用户行为数据&#xff0c;挖…

前后端分离ONLY在线商城系统系统|SpringBoot+Vue+MyBatis+MySQL完整源码+部署教程

&#x1f4a1;实话实说&#xff1a;CSDN上做毕设辅导的都是专业技术服务&#xff0c;大家都要生活&#xff0c;这个很正常。我和其他人不同的是&#xff0c;我有自己的项目库存&#xff0c;不需要找别人拿货再加价&#xff0c;所以能给到超低价格。摘要 随着电子商务的快速发展…

前后端分离“衣依”服装销售平台系统|SpringBoot+Vue+MyBatis+MySQL完整源码+部署教程

摘要 随着电子商务的快速发展&#xff0c;服装销售行业对高效、灵活的管理系统需求日益增长。传统的单机版或前后端耦合的系统架构已难以满足现代企业对快速迭代、高并发访问及跨平台兼容性的需求。服装销售平台需要具备商品管理、订单处理、用户交互等功能&#xff0c;同时还需…

解析HTML表格嵌套问题

在处理HTML表格转换为CSV的过程中,我遇到了一个有趣的问题。让我们来详细探讨一下这个问题,并提供解决方案。 问题背景 假设我们有一个HTML字符串,包含多个表格: <table> <tr><td>A</td>

SpringBoot+Vue 海滨体育馆管理系统平台完整项目源码+SQL脚本+接口文档【Java Web毕设】

摘要 随着体育产业的快速发展&#xff0c;体育馆的管理需求日益复杂化&#xff0c;传统的人工管理模式已无法满足现代化场馆的高效运营需求。海滨体育馆作为一个综合性体育场馆&#xff0c;涉及场地预约、会员管理、设备维护等多方面业务&#xff0c;亟需一套智能化管理系统以提…

探索 qCumber 单元测试框架

在编程领域,单元测试是确保代码质量和可靠性的重要环节。qCumber 是 kdb+/q 语言的一个单元测试框架,专门用于测试 q 脚本。本文将深入探讨如何使用 qCumber 框架进行单元测试,并通过一个具体的实例来展示其应用。 qCumber 简介 qCumber 是一个轻量级的测试框架,适用于 k…

SpringBoot+Vue 墙绘产品展示交易平台平台完整项目源码+SQL脚本+接口文档【Java Web毕设】

摘要 随着城市化进程的加快和艺术文化的普及&#xff0c;墙绘艺术逐渐成为城市美化的重要组成部分&#xff0c;同时也催生了墙绘产品展示与交易的市场需求。传统的墙绘交易模式依赖线下渠道&#xff0c;存在信息不对称、交易效率低等问题。为了解决这些问题&#xff0c;本研究设…

Java Web 网上租赁系统系统源码-SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0【含文档】

摘要 随着互联网技术的快速发展&#xff0c;传统租赁行业正逐步向数字化、智能化转型。网上租赁系统作为一种新型的商业模式&#xff0c;能够有效降低租赁双方的信息不对称问题&#xff0c;提高资源利用率&#xff0c;同时为用户提供便捷的在线租赁服务。该系统通过整合租赁资源…