Java并发容器详解

1. JUC并发容器概述

Java集合容器框架主要有四大类别:List、Set、Queue、Map。常见的ArrayList、LinkedList、HashMap等容器都是非线程安全的。

Java提供了同步容器(如Vector、Hashtable、SynchronizedList)通过synchronized实现同步,但会削弱并发性,降低吞吐量。为解决性能问题,java.util.concurrent包提供了多种并发类容器。

2. CopyOnWriteArrayList

2.1 概述

  • 对应的非并发容器:ArrayList
  • 目标:代替Vector、synchronizedList
  • 原理:利用读多写少的特性,读操作不加锁,写操作时先复制新集合,修改后替换旧引用,通过volatile保证可见性

2.2 应用场景

  1. 读多写少的场景:读取频率远高于写入频率的缓存
  2. 不需要实时更新的数据:如日志缓冲批量写入

2.3 基本使用

// 创建CopyOnWriteArrayList对象
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();// 添加元素
list.add("element1");
list.add("element2");// 设置元素(指定下标)
list.set(0, "newElement");// 获取元素
String element = list.get(0);// 删除元素
list.remove(0);
list.remove("element2");// 其他操作
boolean isEmpty = list.isEmpty();
boolean contains = list.contains("element1");
int size = list.size();
list.clear();

2.4 IP黑名单判定示例

public class CopyOnWriteArrayListDemo {private static CopyOnWriteArrayList<String> blacklist = new CopyOnWriteArrayList<>();// 模拟初始黑名单数据static {blacklist.add("192.168.1.1");blacklist.add("192.168.1.2");blacklist.add("192.168.1.3");}public static void main(String[] args) {// 模拟请求处理Runnable requestHandler = () -> {try {Thread.sleep(new Random().nextInt(1000));} catch (InterruptedException e) {e.printStackTrace();}String clientIP = "192.168.1." + new Random().nextInt(6);if (blacklist.contains(clientIP)) {System.out.println(Thread.currentThread().getName() + " IP " + clientIP + " 命中黑名单,拒绝访问");return;}System.out.println(Thread.currentThread().getName() + " IP " + clientIP + " 允许访问");};// 启动多个请求线程for (int i = 1; i <= 5; i++) {new Thread(requestHandler, "请求-" + i).start();}// 黑名单更新线程new Thread(() -> {try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}String newBlackIP = "192.168.1.4";blacklist.add(newBlackIP);System.out.println("系统更新: 添加新黑名单IP " + newBlackIP);}, "黑名单更新").start();}
}

2.5 实现原理

采用"写时复制"机制:

  1. 写操作时创建新数组,复制原始数组内容
  2. 在新数组上进行修改操作
  3. 将引用指向新数组,通过volatile保证可见性
  4. 读操作直接访问数组,无需加锁

2.6 缺陷

  1. 内存消耗:写操作需要拷贝数组,可能引发GC
  2. 数据一致性:不能保证实时一致性,只能保证最终一致性
  3. 性能问题:数据量大时写操作代价高昂

2.7 Fail-Fast vs Fail-Safe机制

Fail-Fast机制
  • 特点:快速失败,检测到并发修改立即抛出ConcurrentModificationException
  • 实现:java.util包中的集合类(ArrayList、HashMap等)
  • 解决方案
    • 使用synchronized(不推荐,影响性能)
    • 使用CopyOnWriteArrayList(推荐)
Fail-Safe机制
  • 特点:安全失败,在复制的集合上修改,不抛出异常
  • 实现:java.util.concurrent包中的集合类
  • 缺点
    • 数据非实时一致
    • 内存占用更高(需要复制)
    • 可能引起频繁GC

3. ConcurrentHashMap

3.1 概述

  • 对应的非并发容器:HashMap
  • 目标:代替Hashtable、synchronizedMap,支持复合操作
  • 原理
    • JDK6:分段锁机制
    • JDK8:CAS + synchronized

3.2 应用场景

  1. 共享数据的线程安全:多线程环境下的数据读写
  2. 缓存实现:高并发缓存数据结构

3.3 基本使用

// 创建ConcurrentHashMap对象
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();// 添加键值对
map.put("key1", 1);
map.put("key2", 2);// 批量添加
HashMap<String, Integer> tempMap = new HashMap<>();
tempMap.put("key3", 3);
tempMap.put("key4", 4);
map.putAll(tempMap);// 获取值
Integer value = map.get("key1");// 特殊方法
map.putIfAbsent("key1", 100); // 不存在则put,返回null;存在返回当前值
map.remove("key1", 1); // 键值匹配才删除
map.replace("key2", 2, 20); // 键值匹配才替换// 其他操作
boolean isEmpty = map.isEmpty();
int size = map.size();
Set<String> keys = map.keySet();
Collection<Integer> values = map.values();
map.clear();

3.4 单词统计示例

public class ConcurrentHashMapDemo {private static ConcurrentHashMap<String, AtomicLong> wordCountMap = new ConcurrentHashMap<>();private static CountDownLatch latch = new CountDownLatch(3);private static String[] words = {"apple", "banana", "orange", "apple", "banana"};public static void main(String[] args) throws InterruptedException {Runnable counterTask = () -> {for (int i = 0; i < 5; i++) {String word = words[new Random().nextInt(words.length)];// 获取当前计数,不存在则初始化AtomicLong count = wordCountMap.get(word);if (count == null) {AtomicLong newCount = new AtomicLong(0);count = wordCountMap.putIfAbsent(word, newCount);if (count == null) {count = newCount;}}// 增加计数count.incrementAndGet();System.out.println(Thread.currentThread().getName() + ": " + word + " 计数: " + count.get());}latch.countDown();};// 启动多个计数线程for (int i = 1; i <= 3; i++) {new Thread(counterTask, "计数器-" + i).start();}latch.await();System.out.println("最终统计结果: " + wordCountMap);}
}

3.5 数据结构演进

HashTable结构
  • 全表锁,性能低下
JDK1.7 ConcurrentHashMap
  • 结构:Segment数组 + HashEntry数组 + 链表
  • 机制:分段锁,写操作分散到不同段
JDK1.8+ ConcurrentHashMap
  • 结构:数组 + 链表 + 红黑树(同HashMap)
  • 机制:CAS + synchronized
  • 树化条件
    • 链表节点数 ≥ 8(TREEIFY_THRESHOLD)
    • 数组长度 ≥ 64(MIN_TREEIFY_CAPACITY)

4. ConcurrentSkipListMap

4.1 概述

  • 对应的非并发容器:TreeMap
  • 特点:基于跳表实现的线程安全有序Map
  • 优势:支持高并发有序访问和区间查询

4.2 跳表(Skip List)原理

跳表是基于有序链表的概率型数据结构,支持O(log n)时间复杂度的查找、插入、删除操作。

跳表特性
  1. 多层链表结构组成
  2. 每层都是有序链表
  3. 最底层包含所有元素
  4. 高层元素必定在低层出现
  5. 节点包含两个指针:同级下一个元素、下层相同值元素
跳表操作
  • 查找:从最高层开始,向右查找直到大于目标值,然后向下一层继续
  • 插入
    1. 随机确定插入层级K
    2. K大于当前层级时创建新层
    3. 申请新节点并调整指针

4.3 基本使用

public class ConcurrentSkipListMapDemo {public static void main(String[] args) {ConcurrentSkipListMap<Integer, String> skipListMap = new ConcurrentSkipListMap<>();// 添加元素(自动排序)skipListMap.put(3, "Value3");skipListMap.put(1, "Value1");skipListMap.put(4, "Value4");skipListMap.put(2, "Value2");// 获取元素String value = skipListMap.get(2);System.out.println("Key=2的值: " + value);// 遍历元素(有序)System.out.println("按顺序遍历:");for (Integer key : skipListMap.keySet()) {System.out.println(key + " : " + skipListMap.get(key));}// 范围查询System.out.println("Key在1-3之间的元素:");ConcurrentNavigableMap<Integer, String> subMap = skipListMap.subMap(1, true, 3, true);subMap.forEach((k, v) -> System.out.println(k + " : " + v));// 删除元素String removedValue = skipListMap.remove(3);System.out.println("删除的值: " + removedValue);}
}

5. 其他并发容器(部分不常用)

5.1 CopyOnWriteArraySet

  • 对应的非并发容器:HashSet
  • 原理:基于CopyOnWriteArrayList实现
  • 特点:使用addIfAbsent方法保证元素唯一性

5.2 并发Queue

  • ArrayBlockingQueue:数组实现的有界阻塞队列
  • LinkedBlockingQueue:链表实现的可选有界队列
  • ConcurrentLinkedQueue:高性能非阻塞队列
  • PriorityBlockingQueue:支持优先级的无界阻塞队列

5.3 并发Deque

  • ConcurrentLinkedDeque:并发双端队列
  • LinkedBlockingDeque:链表实现的双端阻塞队列

6. 性能考量与最佳实践

6.1 性能影响因素

  1. 并发级别:根据实际并发访问量选择合适容器
  2. 读写比例:读多写少选CopyOnWrite,写多选ConcurrentHashMap
  3. 数据量大小:大数据量考虑ConcurrentSkipListMap
  4. 一致性要求:强一致选Hashtable,弱一致选并发容器

6.2 最佳实践

  1. 明确需求:根据业务场景选择最合适的容器
  2. 性能测试:在实际负载下测试容器性能
  3. 监控GC:关注并发容器可能引起的内存和GC问题
  4. 避免过度设计:简单场景使用简单解决方案
// 容器选型决策示例
public class ContainerSelector {public static <K, V> Map<K, V> createMap(boolean needOrdering, int expectedSize, int concurrencyLevel) {if (needOrdering) {return new ConcurrentSkipListMap<>();} else if (expectedSize > 1000000 || concurrencyLevel > 100) {return new ConcurrentHashMap<>(expectedSize, 0.75f, concurrencyLevel);} else {return new ConcurrentHashMap<>();}}public static <E> List<E> createList(boolean readHeavy, int expectedSize) {if (readHeavy && expectedSize < 10000) {return new CopyOnWriteArrayList<>();} else {return Collections.synchronizedList(new ArrayList<>());}}
}

选型总结

场景特点推荐容器理由
键值对操作,高并发ConcurrentHashMap线程安全,性能优良
大数据量有序访问ConcurrentSkipListMap跳表结构,高效增删
读多写少,数据量小CopyOnWriteArrayList读无锁,写时复制
强一致性要求Hashtable全表锁,保证强一致

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

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

相关文章

SpringAI系列---【SpringA集成OllamaI如何先调用向量库,再把查到的结果一起传给大模型?】

SpringAI如何先调用向量库&#xff0c;再把查到的结果一起传给大模型&#xff1f; 1.引入pom <dependencies><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-model-ollama</artifactId></depend…

告别“测试滞后”:AI实时测试工具在敏捷开发中的落地经验

告别“测试滞后”&#xff1a;AI实时测试工具在敏捷开发中的落地经验 在敏捷开发的“快速迭代”节奏中&#xff0c;测试环节常常成为“拖后腿”的短板。某互联网公司的敏捷团队曾陷入这样的循环&#xff1a;2周迭代周期中&#xff0c;开发用10天完成功能&#xff0c;留给测试的…

K8S-Pod资源对象

一、K8S架构与组件1、K8S架构k8s 总体架构采用了经典的 maste/slave 架构模式&#xff0c;分 master 节点和 worker 节点&#xff0c;节点可以是虚拟机也可以是物理机。K8S组件 master 节点组件Kube-apiserver 用于暴露 Kubernetes API&#xff0c;任何资源请求或调用操作都是通…

PyTorch API 5

文章目录torch.compiler延伸阅读torch.fft快速傅里叶变换辅助函数torch.func什么是可组合的函数变换&#xff1f;为什么需要可组合的函数变换&#xff1f;延伸阅读torch.futurestorch.fx概述编写转换函数图结构快速入门图操作直接操作计算图使用 replace_pattern() 进行子图重写…

基于决策树模型的汽车价格预测分析

一、整体流程概览这份代码实现了一个完整的机器学习预测流程&#xff0c;核心目标是通过汽车的各项特征预测其价格。整体流程分为 6 个主要步骤&#xff1a;模拟生成汽车数据集&#xff08;含价格标签&#xff09;数据预处理&#xff08;清洗、编码、特征选择&#xff09;探索性…

0基础安卓逆向原理与实践:第2章:编程基础与工具链

第2章:编程基础与工具链 2.1 Java编程基础 2.1.1 Java语言特性 Java是安卓应用开发的主要语言,具有以下核心特性: mindmaproot((Java特性))面向对象封装继承多态抽象平台无关字节码JVM一次编译到处运行内存管理自动垃圾回收堆栈管理引用类型安全性字节码验证安全管理器访…

深入理解JVM内存结构:从字节码执行到垃圾回收的全景解析

&#x1f9e0; 深入理解JVM内存结构&#xff1a;从字节码执行到垃圾回收的全景解析 #JVM内存模型 #Java性能优化 #垃圾回收机制 #并发编程一、JVM内存结构全景图二、线程共享区域详解 2.1 堆&#xff08;Heap&#xff09;—— 对象生存的宇宙 存储内容&#xff1a; 所有new创建…

用 C++ 构建高性能测试框架:从原型到生产实战指南

用 C 构建高性能测试框架&#xff1a;从原型到生产实战指南 ​C 测试框架的关键价值​&#xff1a;当你的测试需要每秒处理百万级交易&#xff0c;微秒级延迟要求已成为常态时&#xff0c;Python GC 的暂停便是不可接受的奢侈。 本文将深入探讨如何用 C 构建兼具灵活性和高性能…

【C语言16天强化训练】从基础入门到进阶:Day 4

&#x1f525;个人主页&#xff1a;艾莉丝努力练剑 ❄专栏传送门&#xff1a;《C语言》、《数据结构与算法》、C语言刷题12天IO强训、LeetCode代码强化刷题、洛谷刷题、C/C基础知识知识强化补充、C/C干货分享&学习过程记录 &#x1f349;学习方向&#xff1a;C/C方向 ⭐️人…

C语言:字符函数与字符串函数(1)

在编程的过程中&#xff0c;我们经常会遇到需要处理字符和字符串的情况&#xff0c;为了方便操作字符和字符串&#xff0c;C语言标准库中提供了一系列库函数&#xff0c;接下来我们就学习一下这些函数。 目录 1. 字符分类函数 2. 字母转换函数 3. strlen函数的使用和模拟实现…

数据结构与算法系列(大白话模式)小学生起点(一)

出身&#xff0c;并不重要 &#xff01;&#xff01;&#xff01;&#xff01;只要有恒心&#xff0c;有毅力&#xff0c;肯于付出与学习&#xff0c;皆会取得相应的成就&#xff01;天道酬勤&#xff0c;天行健&#xff0c;君子当自强不息&#xff01;道可道&#xff0c;非常道…

计算机视觉第一课opencv(二)保姆级教学

目录 简介 一、边界填充 1.函数说明 2.案例分析 二、图像运算 1.号运算 2.cv2.add()函数 3.图像加权运算 三、阈值处理 四、图像平滑处理 1.椒盐噪声 2.均值滤波&#xff08;Mean Filtering&#xff09; 3.方框滤波 4. 高斯滤波&#xff08;Gaussian Filtering&am…

DINOv3

一、摘要 https://arxiv.org/pdf/2508.10104 自监督学习有望消除对人工数据标注的需求&#xff0c;使模型能够轻松扩展到大规模数据集和更大规模的架构。由于不针对特定任务或领域进行定制&#xff0c;这种训练范式具有从各种来源学习视觉表示的潜力&#xff0c;能够使用单一…

​​pytest+yaml+allure接口自动化测试框架

高薪必备&#xff01;18K接口自动化测试框架落地全流程&#xff5c;零基础到实战通关前言# 自动化测试&#xff0c;是目前测试行业一项比较普遍的测试技术了&#xff0c;之前的以UI自动化测试为主&#xff0c;现在的以接口自动化测试为主&#xff0c;无论技术更迭&#xff0c;…

LeetCode每日一题,2025-8-20

统计全为1的正方形子矩阵 这题是正方形&#xff0c;比较简单 暴力就是二维前缀和。 或者用dp&#xff0c;dp[i][j]表示以i&#xff0c;j为右下角的最大正方形的边长&#xff0c;它由(i-1,j),(i,j-1),(i-1,j-1)三者共同决定&#xff0c;通过找规律可知&#xff0c;由三个的最小值…

在Excel启动时直接打开多个Excel文件

如果我们这段时间每天都要打开几个相同的Excel文件开展工作&#xff0c;可以把这几个文件放到一个文件夹&#xff08;如果原来就在不同的文件夹&#xff0c;就把快捷方式放到同一个文件夹&#xff09;&#xff0c;然后在Excel选项中设置启动时打开这个文件夹中的文件即可。注&a…

对象存储 COS 端到端质量系列 —— 终端网络诊断工具

背景 在COS终端SDK的众多功能中&#xff0c;文件上传功能的使用颇为频繁。鉴于此&#xff0c;提升文件上传的成功率便显得至关重要。众多导致上传失败的因素里&#xff0c;由网络问题引发的故障无疑是其中影响上传成功率的关键因素之一&#xff0c;同时也是最难以把控的要素。…

Flask高效数据库操作指南

Flask-SQLAlchemy 数据库操作关于Flask数据库Flask中没有指定使用的数据库&#xff0c;可以自由选择不管你是使用关系型数据库&#xff0c;还是非关系型数据库都可以&#xff0c;不像django提供了orm 数据库抽象层&#xff0c;可以直接采用对象的方式操作数据库。但是为了开发效…

Camera相机人脸识别系列专题分析之十九:MTK ISP6S平台FDNode原生代码

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了: 这一篇我们开始讲: 目录 一、问题背景 二、MTK ISP6S平台FDNodeImp.cpp 2.1:原生代码

S32K3 的图形化配置和EB配置mcal差异

32K3系列的图形化配置工具&#xff08;如S32 Design Studio, S32DS&#xff09;与EB配置工具&#xff08;基于EB tresos Studio&#xff09;在配置MCAL&#xff08;Microcontroller Abstraction Layer&#xff09;时存在关键差异&#xff0c;主要体现在工具环境、配置流程、代码…