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

【Java】如何保证集合的线程安全?

【Java】如何保证集合的线程安全?

文章目录

    • 1. CopyOnWriteArrayList
    • 2. ConcurrentHashMap
    • 3. Collections.synchronizedList
    • 4. 其他线程安全集合
      • BlockingQueue 系列
      • ConcurrentLinkedQueue
    • 5. 性能对比和使用建议
    • 6. 实际应用示例

1. CopyOnWriteArrayList

适用场景:读多写少的并发场景

import java.util.concurrent.CopyOnWriteArrayList;public class CopyOnWriteExample {public static void main(String[] args) {CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();// 写操作 - 会复制整个底层数组list.add("A");list.add("B");// 读操作 - 无需加锁,性能高for (String item : list) {System.out.println(item); // 线程安全地遍历}// 批量操作list.addAll(List.of("C", "D"));}
}
写操作后
写操作时
写操作前
复制
替换引用
元素A
新数组成为主数组
元素B
新元素D
元素C
元素A
创建新数组
元素B
新元素D
元素C
元素A
原始数组
元素B
元素C

特点

  • 写操作时复制整个数组,开销大 ; 复制新数组 → 修改新数组 → 替换引用
  • 读操作不需要锁,性能极高 ; 直接访问当前数组,无锁
  • 迭代器不会抛出ConcurrentModificationException; 基于创建时的快照,不会看到后续修改
  • 数据最终一致性,不保证实时一致性

2. ConcurrentHashMap

适用场景:高并发键值对存储

import java.util.concurrent.ConcurrentHashMap;public class ConcurrentHashMapExample {public static void main(String[] args) {ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();// 基本操作map.put("key1", 1);map.putIfAbsent("key1", 2); // 如果不存在则插入// 原子操作map.compute("key2", (k, v) -> v == null ? 1 : v + 1);// 线程安全的遍历map.forEach((k, v) -> System.out.println(k + ": " + v));// 搜索操作Integer result = map.search(1, (k, v) -> v > 0 ? k : null);}
}
锁机制
ConcurrentHashMap 结构
Table - 数组 + 链表/红黑树
CAS/synchronized
CAS/synchronized
CAS/synchronized
线程1
线程2
线程3
Map主体
Node
Node
红黑树结构
TreeNode
TreeNode
桶0: Node
Table
桶1: Node
桶2: TreeBin
桶N: Node

特点

  • 分段锁(Java 7)或 CAS + synchronized(Java 8+); 每个桶独立加锁
  • 高并发读写性能优秀 ; 通常无锁
  • 不会锁住整个Map; 只锁单个桶或使用CAS
  • 提供原子操作方法(volatile读取)

3. Collections.synchronizedList

适用场景:需要将现有集合转换为线程安全版本

import java.util.*;public class SynchronizedCollectionExample {public static void main(String[] args) {// 包装普通ArrayListList<String> syncList = Collections.synchronizedList(new ArrayList<>());// 基本操作 - 自动加锁syncList.add("A");syncList.add("B");// 遍历时需要手动同步synchronized(syncList) {Iterator<String> iterator = syncList.iterator();while(iterator.hasNext()) {System.out.println(iterator.next());}}// 同样适用于其他集合Map<String, String> syncMap = Collections.synchronizedMap(new HashMap<>());Set<String> syncSet = Collections.synchronizedSet(new HashSet<>());}
}
方法调用流程
包装器模式
包装
只有一个线程进入
获取锁
线程1调用add
线程2调用get
线程3调用remove
执行原始集合方法
释放锁
线程1继续
线程2继续
线程3继续
原始ArrayList
Collections.synchronizedList
互斥锁 Mutex

特点

  • 在所有方法上加 synchronized 锁 ; 所有操作共用一把锁
  • 性能相对较低 ; 方法级别同步
  • 遍历时需要手动同步
  • 适合低并发场景 ; 高并发时竞争激烈
内存开销
写性能
读性能
极高
极低
★☆☆☆☆
CopyOnWriteArrayList
★★★☆☆
ConcurrentHashMap
★★★★☆
SynchronizedList
★☆☆☆☆
CopyOnWriteArrayList
★★★★☆
ConcurrentHashMap
★★☆☆☆
SynchronizedList
★★★★★
CopyOnWriteArrayList
★★★★☆
ConcurrentHashMap
★★☆☆☆
SynchronizedList

4. 其他线程安全集合

BlockingQueue 系列

import java.util.concurrent.*;public class BlockingQueueExample {public static void main(String[] args) throws InterruptedException {// 有界队列BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);// 生产者queue.put("item1"); // 阻塞直到有空间queue.offer("item2", 1, TimeUnit.SECONDS); // 超时等待// 消费者String item = queue.take(); // 阻塞直到有元素item = queue.poll(1, TimeUnit.SECONDS); // 超时等待}
}

ConcurrentLinkedQueue

import java.util.concurrent.ConcurrentLinkedQueue;public class ConcurrentQueueExample {public static void main(String[] args) {ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();// 无界非阻塞队列queue.offer("A");queue.offer("B");String item = queue.poll(); // 非阻塞}
}

5. 性能对比和使用建议

集合类型适用场景性能特点一致性
CopyOnWriteArrayList读多写少读快写慢最终一致
ConcurrentHashMap高并发K-V读写都快弱一致
Collections.synchronizedList低并发读写都慢强一致
BlockingQueue生产者消费者阻塞操作强一致

6. 实际应用示例

public class ThreadSafeCache {private final ConcurrentHashMap<String, Object> cache = new ConcurrentHashMap<>();private final CopyOnWriteArrayList<String> accessLog = new CopyOnWriteArrayList<>();public void put(String key, Object value) {cache.put(key, value);accessLog.add("PUT: " + key);}public Object get(String key) {accessLog.add("GET: " + key);return cache.get(key);}// 批量获取 - 线程安全public Map<String, Object> getAll(Set<String> keys) {Map<String, Object> result = new HashMap<>();for (String key : keys) {Object value = cache.get(key);if (value != null) {result.put(key, value);}}return result;}
}
读多写少
键值存储
列表/集合
高并发
低并发
简单同步
队列操作
选择线程安全集合
主要操作类型?
CopyOnWriteArrayList
并发级别?
同步需求?
ConcurrentHashMap
Collections.synchronizedMap
Collections.synchronizedList
BlockingQueue
场景: 监听器列表, 配置信息
场景: 缓存, 计数器
场景: 临时数据集合
场景: 生产者消费者
场景: 配置映射

选择建议

  • 高并发读CopyOnWriteArrayList ; 空间换时间,适合很少修改的读密集型场景
  • 高并发K-VConcurrentHashMap ; 分段锁/CAS,适合高并发读写
  • 简单同步Collections.synchronizedXxx ; 全局锁,简单但性能较差
  • 任务队列BlockingQueue
  • 无锁队列ConcurrentLinkedQueue
http://www.dtcms.com/a/565730.html

相关文章:

  • linux系统中进程通信之管道
  • ip下的网站吗wordpress建站企业
  • 企业官网项目方案(Vue3+Node 全栈)
  • 最火的传奇手游网站网站文章分类
  • 算法<C++>——二分查找
  • MIDI协议与Arduino编程
  • 【开题答辩全过程】以 儿童口腔诊所私域管理系统为例,包含答辩的问题和答案
  • 什么网站做app好网站建设的后如何发布
  • 从零开始的Qt开发指南:(二)使用Qt Creator构建项目与Qt底层机制的深度解析
  • UVa 1326 Jurassic Remains
  • Readest(电子书阅读器) v0.9.91
  • Flink 优化-数据倾斜
  • 遵义网站网站建设江阴便宜做网站
  • 大模型RLHF:PPO原理与源码解读
  • Mojo变量知识点解读
  • Linux之rsyslog(2)输入输出配置
  • 整体设计 全面梳理复盘 之17 三套表制表的支持和支撑以及编程基础 之2
  • 凯文·凯利《2049:未来10000天的可能》
  • 网站百度建设高端网站设计百家号
  • ctypes.pythonapi.PyThreadState_SetAsyncExc作用详解
  • pyside6常用控件: QPushButton()按钮切换、带图片的按钮
  • Python逻辑运算符
  • MinGW下载、安装和使用教程(附安装包,适合新手)
  • lol做任务领头像网站微商城网站建设平台
  • 百日挑战——单词篇(第十二天)
  • (单调队列、ST 表)洛谷 P2216 HAOI2007 理想的正方形 / P2219 HAOI2007 修筑绿化带
  • Spark RDD 编程从驱动程序到共享变量、Shuffle 与持久化
  • 网站 面包屑网站开发工作流审批流
  • 网站建设广金手指六六十四在线建站系统
  • 排序还有分页