一、线程安全List
1. 同步包装类
List<String> syncList = Collections.synchronizedList(new ArrayList<>());
-
通过
synchronized方法实现线程安全 -
迭代时需要手动加锁
-
适合低并发场景
2. CopyOnWriteArrayList(推荐)
List<String> copyList = new CopyOnWriteArrayList<>();
-
写时复制:修改时创建新数组,读操作无锁
-
适合读多写少场景
-
迭代器是快照,不会抛出
ConcurrentModificationException
3. Vector(已过时)
Vector<String> vector = new Vector<>();
-
JDK1.0遗留类,方法使用
synchronized修饰 -
性能较差,不推荐使用
二、线程安全Map
1. ConcurrentHashMap(推荐)
java
Map<String, Object> concurrentMap = new ConcurrentHashMap<>();
-
JDK1.7:分段锁(Segment)
-
JDK1.8+:
synchronized+ CAS + 红黑树 -
高并发下性能优秀
-
不允许null键/值
2. Collections.synchronizedMap
java
Map<String, Object> syncMap = Collections.synchronizedMap(new HashMap<>());
-
使用
synchronized包装所有方法 -
迭代时需要手动同步
3. ConcurrentSkipListMap
java
Map<String, Object> skipMap = new ConcurrentSkipListMap<>();
-
基于跳表实现的有序并发Map
-
支持范围查询
4. Hashtable(已过时)
java
Hashtable<String, Object> table = new Hashtable<>();
- 与Vector类似,全表锁性能差
三、选择策略
| 场景 | List推荐方案 | Map推荐方案 |
|---|---|---|
| 读多写少 | CopyOnWriteArrayList |
ConcurrentHashMap |
| 写多读少 | Collections.synchronizedList |
ConcurrentHashMap |
| 需要有序 | - | ConcurrentSkipListMap |
| 低并发 | 同步包装类 | 同步包装类 |
四、注意事项
-
复合操作问题:
java// 即使使用ConcurrentHashMap,以下操作仍然非原子 if (!map.containsKey(key)) { map.put(key, value); // 可能存在竞态条件 } // 应使用 map.putIfAbsent(key, value); -
迭代器弱一致性:
-
并发集合的迭代器是弱一致的
-
不保证迭代时看到所有更新
-
-
性能考量:
-
CopyOnWriteArrayList写操作昂贵(复制数组) -
ConcurrentHashMap扩容时效率较高
-
五、JDK8+增强
java
// ConcurrentHashMap的原子操作
concurrentMap.computeIfAbsent(key, k -> createValue(k));
concurrentMap.merge(key, value, (oldVal, newVal) -> mergeFunction(oldVal, newVal));
// 批量操作
concurrentMap.forEach(parallelismThreshold, action);
concurrentMap.search(parallelismThreshold, searchFunction);
最佳实践
-
优先使用
java.util.concurrent包下的并发集合 -
明确业务场景的读写比例
-
使用原子方法避免复合操作竞态条件
-
考虑使用
ThreadLocal减少竞争 -
高并发场景避免使用
Collections.synchronizedXXX
高并发环境下线程安全的去重List实现方案
一、核心解决方案
1. 使用 CopyOnWriteArraySet
java
Set<String> uniqueSet = new CopyOnWriteArraySet<>();
// 自动去重,线程安全
uniqueSet.add("item1");
uniqueSet.add("item1"); // 不会被添加
特点:
-
内部使用
CopyOnWriteArrayList实现 -
添加时会遍历检查是否已存在(O(n)复杂度)
-
适合读多写少的场景
-
保证元素唯一性
2. 使用 ConcurrentHashMap 模拟去重List
java
// 使用ConcurrentHashMap模拟去重List
Map<String, Boolean> map = new ConcurrentHashMap<>();
List<String> list = Collections.synchronizedList(new ArrayList<>());
public boolean addIfAbsent(String item) {
if (map.putIfAbsent(item, Boolean.TRUE) == null) {
list.add(item);
return true;
}
return false;
}