Java Collections工具类提供同步化(如synchronizedList)和只读控制(如unmodifiableList)两类包装能力,均返回新视图而不修改原集合,但需注意迭代安全、浅只读及现代替代方案。

Java 中的 Collections 工具类提供了两类关键能力:让普通集合支持多线程安全访问(同步化),以及阻止后续修改、保障数据一致性(只读控制)。这两类操作都通过包装原集合实现,不改变原始对象,但返回的新视图具备新行为。
同步化集合:让 ArrayList/HashMap 等支持多线程安全
ArrayList、HashMap、HashSet 等默认是非线程安全的。多个线程同时读写可能引发 ConcurrentModificationException 或数据丢失。Collections 提供了包装方法,为它们加上内置锁:
-
Collections.synchronizedList(list)→ 返回线程安全的 List 视图 -
Collections.synchronizedMap(map)→ 返回线程安全的 Map 视图 -
Collections.synchronizedSet(set)→ 返回线程安全的 Set 视图
注意:同步仅保证单个操作原子性(如 add() 或 get()),但复合操作(如“先检查再插入”)仍需手动加锁或改用 ConcurrentHashMap 等并发集合。
只读控制:禁止任何修改操作
只读不是“不可变”的完全等价——它只是拒绝所有修改方法调用(如 add、remove、put),一旦尝试就会抛出 UnsupportedOperationException。常用方式有三类:
-
Collections.unmodifiableList(list):将已有列表转为只读视图(底层仍引用原 list,若原 list 被外部修改,只读视图内容也会变) -
Collections.emptyList()、Collections.emptyMap()、Collections.emptySet():返回不可变空集合,常用于避免null判断和NullPointerException -
Collections.singletonList("x")、Collections.singleton("x")、Collections.singletonMap("k", "v"):生成含单个元素的不可变集合,轻量且线程安全
典型误用与注意事项
容易忽略的关键细节:
- 同步集合不能解决迭代时的并发修改问题:即使用了
synchronizedList,遍历时仍需手动同步整个迭代块(如synchronized(list) { for(...) {...} }) - 只读视图是“浅只读”:如果集合中存的是可变对象(如
new ArrayList),对象自身仍可被修改() -
unmodifiableXxx()不阻止原始集合被修改:它只是包装,若原 list 后续被其他引用修改,只读视图看到的内容也会变 - 优先考虑更现代的替代方案:如
CopyOnWriteArrayList、ConcurrentHashMap、ImmutableList.of()(来自 Guava)或 Java 10+ 的List.copyOf(),它们在语义和性能上更清晰可靠
实用组合示例
常见安全初始化模式:
- 对外提供只读配置列表:
return Collections.unmodifiableList(new ArrayList(configList)) - 防止空指针:
public SetgetTags() { return tags != null ? tags : Collections.emptySet(); } - 构造默认单值响应:
return Collections.singletonList("default");











