线程安全集合
线程安全集合用于多线程并发访问场景,分为同步包装类和并发集合类两大类。
线程安全集合分类
| 类别 | 代表类 | 特点 | 适用场景 |
|---|---|---|---|
| 同步包装类 | Vector、Hashtable、Collections.synchronizedXxx | 全表锁,性能低 | 低并发场景 |
| 并发集合 | ConcurrentHashMap、ConcurrentLinkedQueue | 分段锁/CAS,高并发性能好 | 高并发场景 |
| CopyOnWrite | CopyOnWriteArrayList、CopyOnWriteArraySet | 写时复制,读无锁 | 读多写少 |
同步包装类
Collections.synchronizedXxx
Java
List<String> syncList = Collections.synchronizedList(new ArrayList<>());
Set<String> syncSet = Collections.synchronizedSet(new HashSet<>());
Map<String, String> syncMap = Collections.synchronizedMap(new HashMap<>());
注意:遍历同步集合需要手动加锁:
Java
List<String> syncList = Collections.synchronizedList(new ArrayList<>());
synchronized (syncList) { // 遍历时必须加锁
for (String s : syncList) {
// 遍历逻辑
}
}
Vector 和 Hashtable
Java
Vector<String> vector = new Vector<>(); // 同步的 ArrayList
Hashtable<String, String> hashtable = new Hashtable<>(); // 同步的 HashMap
不建议使用:Vector 和 Hashtable 是遗留类,性能差,推荐使用并发集合替代。
ConcurrentHashMap
特点
- JDK 7:分段锁(Segment),16 个段独立锁
- JDK 8+:CAS + synchronized,更细粒度(桶级别)
- 读操作无锁,写操作只锁单个桶
- 性能远优于 Hashtable
使用示例
Java
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
// 基本操作
map.put("key", 1);
map.get("key");
map.remove("key");
// 原子复合操作
map.putIfAbsent("key", 1); //不存在才放入
map.computeIfAbsent("key", k -> 1); // 不存在才计算放入
map.replace("key", 1, 2); // 值为1才替换为2
注意:ConcurrentHashMap 不允许 null 键或 null 值。
CopyOnWriteArrayList
特点
- 写时复制:每次写操作复制整个数组
- 读操作无锁,性能极高
- 写操作开销大,适合读多写少
使用示例
Java
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
// 读操作(无锁,快)
String s = list.get(0);
// 写操作(复制整个数组,慢)
list.add("newElement");
list.remove(0);
list.set(0, "updated");
适用场景
- 读多写少:如事件监听器列表、配置列表
- 遍历频繁:遍历不需要加锁
- 不适用:写操作频繁的场景
ConcurrentLinkedQueue
无界并发队列,基于 CAS 实现:
Java
ConcurrentLinkedQueue<String> queue = new ConcurrentLinkedQueue<>();
queue.offer("element"); // 入队
String e = queue.poll(); // 出队(空返回null)
String e = queue.peek(); // 查看队头(不移除)
BlockingQueue 阻塞队列
Java
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(100);
// 阻塞操作
queue.put("element"); // 队满阻塞
String e = queue.take(); // 队空阻塞
// 非阻塞操作(带超时)
queue.offer("element", 3, TimeUnit.SECONDS); // 超时入队
String e = queue.poll(3, TimeUnit.SECONDS); // 超时出队
要点总结
- 同步包装类:全表锁,性能低,遍历需手动加锁
- ConcurrentHashMap:分段锁/CAS,高并发性能好,推荐使用
- CopyOnWriteArrayList:写时复制,读无锁,适合读多写少
- ConcurrentLinkedQueue:无界并发队列,基于 CAS
- BlockingQueue:阻塞队列,适合生产者-消费者模式
- 选择原则:高并发用 ConcurrentHashMap,读多写少用 CopyOnWrite
📝 发现内容有误?点击此处直接编辑