并发容器(Collections)

一、并发安全问题根源

1. List(如ArrayList)
  • 问题表现 :多线程同时调用addremove等方法时,可能抛出ConcurrentModificationException或导致数据不一致。
  • 根本原因
    • 非原子性操作 :如add操作的流程(检查容量→扩容→插入)在多线程下可能被中断。
    • 结构性修改冲突:多线程同时修改集合结构(如扩容)导致内部数组索引混乱。
2. Set(如HashSet)
  • 问题表现:HashSet底层基于HashMap,多线程插入可能丢失数据或触发异常。
  • 根本原因
    • HashMap的线程不安全:HashSet依赖的HashMap在多线程下可能因哈希冲突或扩容导致死循环或数据丢失。
3. Map(如HashMap)
  • 问题表现 :多线程并发插入或扩容时,可能造成死循环(JDK 1.7)或数据覆盖(JDK 1.8+)。
  • 根本原因
    • 哈希表扩容冲突 :多线程同时触发扩容(resize)时,链表或红黑树重构过程中节点引用混乱。
    • 非原子性put操作:多线程同时插入同一哈希桶可能导致数据覆盖。

二、解决方案

1. List的线程安全实现
  • Collections.synchronizedList

    通过同步方法包装普通List,保证原子性但性能较低:

    java 复制代码
    List<String> list = Collections.synchronizedList(new ArrayList<>());
  • CopyOnWriteArrayList (推荐)

    写操作复制新数组,读操作无锁,适合读多写少场景:

    java 复制代码
    List<String> list = new CopyOnWriteArrayList<>();
2. Set的线程安全实现
  • Collections.synchronizedSet

    同步方法包装普通Set:

    java 复制代码
    Set<String> set = Collections.synchronizedSet(new HashSet<>());
  • CopyOnWriteArraySet (推荐)

    基于CopyOnWriteArrayList实现,适合元素少、读多写少:

    java 复制代码
    Set<String> set = new CopyOnWriteArraySet<>();
3. Map的线程安全实现
  • ConcurrentHashMap(推荐)

    • JDK 1.7:分段锁(Segment),降低锁粒度。
    • JDK 1.8+:CAS + synchronized锁单个哈希桶,并发性能更高。
    java 复制代码
    Map<String, String> map = new ConcurrentHashMap<>();
  • Collections.synchronizedMap

    同步方法包装普通Map,适用于低并发:

    java 复制代码
    Map<String, String> map = Collections.synchronizedMap(new HashMap<>());

三、对比与选型

集合类型 非安全类 安全实现方案 适用场景
List ArrayList CopyOnWriteArrayList 读多写少(如配置信息)
Collections.synchronizedList 简单同步需求
Set HashSet CopyOnWriteArraySet 元素少、读多写少
Collections.synchronizedSet 低并发场景
Map HashMap ConcurrentHashMap 高并发读写(首选)
Collections.synchronizedMap 兼容旧代码或低并发需求

四、注意事项

  1. 性能权衡
    • CopyOnWriteArrayList每次写操作复制数组,写频繁时性能差
    • ConcurrentHashMap在JDK 1.8+中优化为CAS+锁,性能接近无锁。
  2. 避免误区
    • VectorHashtable通过全表锁实现安全,但高并发下性能差,不推荐使用。
  3. 开发建议
    • 默认使用ConcurrentHashMap替代HashMapCopyOnWriteArrayList替代ArrayList
    • 若需强一致性(如金融场景),需结合显式锁(如ReentrantLock)或数据库事务。

通过选择适合的并发容器,可避免ConcurrentModificationException、数据丢失等问题,同时平衡性能与线程安全。

相关推荐
MacroZheng4 分钟前
还在用WebSocket实现即时通讯?试试MQTT吧,真香!
java·spring boot·后端
稚辉君.MCA_P8_Java18 分钟前
豆包 Java的23种设计模式
java·linux·jvm·设计模式·kubernetes
tanyongxi6619 分钟前
C++ 特殊类设计与单例模式解析
java·开发语言·数据结构·c++·算法·单例模式
遗憾皆是温柔21 分钟前
24. 什么是不可变对象,好处是什么
java·开发语言·面试·学习方法
midsummer_woo27 分钟前
基于springboot的IT技术交流和分享平台的设计与实现(源码+论文)
java·spring boot·后端
Peter(阿斯拉)38 分钟前
[Java性能优化]_[时间优化]_[字符串拼接的多种方法性能分析]
java·性能优化·stringbuilder·string·字符串拼接·stringbuffer·时间优化
困鲲鲲2 小时前
CPP多线程2:多线程竞争与死锁问题
c++·多线程·死锁
水痕012 小时前
gin结合minio来做文件存储
java·eureka·gin
寒士obj2 小时前
Spring事物
java·spring
柯南二号3 小时前
【Java后端】Spring Boot 集成 MyBatis-Plus 全攻略
java·spring boot·mybatis