CopyOnWriteArraySet
CopyOnWriteArraySet<String> copyOnWriteArraySet = new CopyOnWriteArraySet<>();
原理
和CopyOnWriteArrayList实现原理一样,采用读写分离的并发策略,读操作的时候不加锁,写操作时创建底层数据的新副本,在新副本上执行写操作,写操作结束后将原引用指向新的容器。适合读多写少的场景。
特点
- 读操作性能高
- 当使用迭代器遍历时,在遍历的间隔中如果修改了集合,不会抛出ConcurrentModificationException异常。
- 由于要复制新副本,会占用较大内存
- 写操作时在新的副本上操作,此时的读操作还是在旧副本上,所以无法保证实时性
- 大量写操作性能很差
Collections.synchronizedSet()
HashSet<String> hashSet = new HashSet<>();
Set<String> synchronizedSet = Collections.synchronizedSet(hashSet);
原理
在原先Set的每一个方法上都加上synchronized关键字
特点
- 性能较差
- 遍历间隔中如果修改了集合,仍会抛出异常ConcurrentModificationExceptions
Collections.newSetFromMap()
Set<String> setFromMap = Collections.newSetFromMap(new ConcurrentHashMap<>());
原理
封装了ConcurrentHashMap,利用ConcurrentHashMap的性质确保生成的Set是线程安全的。
特点
- 该方法必须传入一个空的map
- 性能较好,ConcurrentHashMap是分区的,写操作时对应的分区时是synchronized的,读操作与其他读操作、写操作是完全并发的(但可能没法看到当前正在写入的更改的结果)
- 迭代器创建后可能会看到变化,也可能看不到变化,而且批量操作不是原子操作
- reSize操作较慢,因此在初始化时最好能够指定大小(3/4满时就会reSize)
- 需要hashCode()方法有较好的性能
- 不允许再和传入的map做交互
ConcurrentHashMap.newKeySet()
ConcurrentHashMap.KeySetView<String, Boolean> keySetView = ConcurrentHashMap.newKeySet();
原理
jdk1.8以后引入的特性,是ConcurrentHashMap的特性的一部分
特点
- 与上面提到的Collections.newSetFromMap(new ConcurrentHashMap<>())相似