多线程环境中安全使用集合
2026/8/24大约 1 分钟
多线程环境中安全使用集合
集合 API 的线程安全性,以及多线程遍历时如何正确同步。
集合的线程安全性
- 最初设计的
Vector和Hashtable是线程安全的(添加/删除元素的方法是同步的) - 但只有单个线程交互时,获取/释放对象锁是浪费,滥用同步还可能带来死锁
- 因此集合本质上是非多线程安全的,多线程交互时需要额外措施
Collections 同步包装方法
Collections 类提供静态方法,用同步方法封装非同步集合:
| 方法 | 作用 |
|---|---|
synchronizedCollection(Collection c) | 包装 Collection |
synchronizedList(List l) | 包装 List |
synchronizedMap(Map m) | 包装 Map |
synchronizedSet(Set s) | 包装 Set |
synchronizedSortedMap(SortedMap sm) | 包装 SortedMap |
synchronizedSortedSet(SortedSet ss) | 包装 SortedSet |
正确用法
List list = Collections.synchronizedList(new ArrayList());注意:立即封装,不要保留对未同步化 ArrayList 的直接引用(直接封装匿名实例是最安全途径)。否则其他线程可直接引用 ArrayList 执行非同步修改。
多线程安全遍历
Collections.synchronizedList 包装后,迭代仍需手动同步——Iterator 遍历时,应阻止其他线程添加或删除元素:
List wordList = Collections.synchronizedList(new ArrayList());
wordList.add("A");
wordList.add("B");
// 迭代时获取 wordList 的对象锁,阻塞其他线程修改
synchronized (wordList) {
Iterator iter = wordList.iterator();
while (iter.hasNext()) {
String s = (String) iter.next();
System.out.println(s);
}
}相对线程安全
大部分线程安全类都是相对线程安全的:保证对对象的单独操作是安全的,但对于特定的连续调用,需要在调用端使用额外的同步手段(如"先检查再操作"的组合操作),例如 Vector、Hashtable、Collections.synchronizedXxx() 包装的集合。