在Java中,线程安全集合是用于多线程环境下保证数据一致性和操作安全性的重要工具。以下是Java线程安全集合的分类及详细说明:
一、传统同步集合
通过同步方法(如synchronized
关键字)实现线程安全,但性能较低:
-
Vector
- 线程安全的动态数组,方法均用
synchronized
修饰。 - 性能较差,推荐使用
CopyOnWriteArrayList
或Collections.synchronizedList()
替代。
- 线程安全的动态数组,方法均用
-
Hashtable
- 线程安全的哈希表,所有方法同步。
- 已被
ConcurrentHashMap
取代,后者提供更好的并发性能。
-
同步包装类
- 使用
Collections
工具类包装非线程安全集合:List<String> syncList = Collections.synchronizedList(new ArrayList<>()); Map<String, String> syncMap = Collections.synchronizedMap(new HashMap<>());
- 缺点:迭代时需手动加锁,否则可能抛出
ConcurrentModificationException
。
- 使用
二、Java并发集合(java.util.concurrent包)
为高并发场景设计,采用更高效的锁机制或无锁技术:
-
ConcurrentHashMap
- 线程安全的哈希表,Java 8前使用分段锁,之后改为CAS和
synchronized
优化。 - 支持高并发读写,
get()
操作无锁。 - 提供原子方法如
putIfAbsent()
。
- 线程安全的哈希表,Java 8前使用分段锁,之后改为CAS和
-
CopyOnWriteArrayList / CopyOnWriteArraySet
- 写时复制:写操作复制整个数组,适用于读多写少的场景。
- 迭代器基于创建时的数据快照,避免
ConcurrentModificationException
。 - 写操作成本高,频繁修改时不推荐。
-
ConcurrentLinkedQueue / ConcurrentLinkedDeque
- 基于链表的无界非阻塞队列,使用CAS实现线程安全。
- 适用于高并发环境下的生产者-消费者模型。
-
ConcurrentSkipListMap / ConcurrentSkipListSet
- 基于跳表(Skip List)的线程安全有序集合。
- 支持并发访问的有序Map和Set。
三、阻塞队列(BlockingQueue)
实现生产者-消费者模型,支持阻塞操作:
-
ArrayBlockingQueue
- 有界队列,基于数组实现,使用ReentrantLock保证线程安全。
-
LinkedBlockingQueue
- 可选有界或无界(默认
Integer.MAX_VALUE
),基于链表。
- 可选有界或无界(默认
-
PriorityBlockingQueue
- 无界优先级队列,元素按自然顺序或Comparator排序。
-
SynchronousQueue
- 不存储元素的队列,每个插入操作需等待另一个线程的移除操作。
四、使用场景建议
- 高并发读写Map:
ConcurrentHashMap
- 读多写少List/Set:
CopyOnWriteArrayList
/CopyOnWriteArraySet
- 有序并发集合:
ConcurrentSkipListMap
/ConcurrentSkipListSet
- 生产者-消费者模型:
BlockingQueue
实现类(如LinkedBlockingQueue
) - 低并发兼容旧代码:同步包装类或
Vector
/Hashtable
五、注意事项
- 复合操作:即使使用线程安全集合,组合多个方法(如
if (!map.containsKey(k)) map.put(k, v)
)仍需同步或使用原子方法(如ConcurrentHashMap.putIfAbsent()
)。 - 迭代器弱一致性:并发集合的迭代器可能不反映最新修改(如
ConcurrentHashMap
),而CopyOnWrite
系列迭代器基于快照。 - 性能权衡:根据读写比例选择合适实现,例如
CopyOnWrite
写性能差,但读无需锁。
合理选择线程安全集合,能在保证线程安全的同时,最大化提升并发性能。
(望各位潘安、各位子健/各位彦祖、于晏不吝赐教!多多指正!🙏)