在Java多线程编程中,如果多个线程同时操作同一个Set集合,使用HashSet或TreeSet都可能产生数据错乱、抛出ConcurrentModificationException等问题。ConcurrentSkipListSet是java.util.concurrent包中提供的线程安全且有序的集合实现,它内部基于跳表结构,能够在无外部锁的情况下保证线程安全,非常适合读多写少或需要有序性的并发场景。

什么是ConcurrentSkipListSet
ConcurrentSkipListSet实现了NavigableSet接口,元素按自然顺序或指定比较器排序。它的所有增删查操作都是线程安全的,并且迭代器不会抛出并发修改异常,但迭代器反映的是迭代开始时的集合状态快照。
如何创建与使用
我们可以直接通过无参构造或有比较器的构造来创建实例。以下代码展示基本用法:
import java.util.concurrent.ConcurrentSkipListSet;
public class Demo {
public static void main(String[] args) {
// 创建线程安全的跳表集合
ConcurrentSkipListSet<String> set = new ConcurrentSkipListSet<>();
// 多线程添加元素
Runnable task = () -> {
for (int i = 0; i < 5; i++) {
set.add(Thread.currentThread().getName() + "-" + i);
}
};
Thread t1 = new Thread(task, "A");
Thread t2 = new Thread(task, "B");
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
// 安全遍历
for (String s : set) {
System.out.println(s);
}
System.out.println("size=" + set.size());
}
}
保证线程安全的关键点
- 内部使用跳表加CAS等无锁算法,多个写线程可并发执行。
- add、remove、contains等操作都是原子性的,调用方无需加锁。
- 批量操作如addAll不保证整体原子性,需要业务层控制。
- 迭代器弱一致性,不会抛异常,但可能不反映最新修改。
与其他线程安全方案对比
| 方案 | 线程安全 | 有序性 | 性能特点 |
|---|---|---|---|
| Collections.synchronizedSet | 是 | 取决于原Set | 读写均加锁,并发度低 |
| ConcurrentSkipListSet | 是 | 天然有序 | 高并发,无锁读 |
| CopyOnWriteArraySet | 是 | 否 | 写贵读便宜,适合读极多写极少 |
使用建议
当业务需要线程安全且元素有序的Set时,优先选择ConcurrentSkipListSet。如果只要求安全不要求有序,可考虑ConcurrentHashMap.newKeySet()。注意它不允许null元素,插入null会抛NullPointerException。
合理使用并发容器能显著降低多线程编程复杂度,但依然要理解其弱一致性和非原子批量操作的边界。
JavaConcurrentSkipListSet线程安全修改时间:2026-07-28 05:51:09