在java中,针对写多读少的场景,首选`concurrenthashmap.newkeyset()`创建的并发哈希集,而非传统的`synchronizedset`或手动加锁的`hashset`。核心做法是调用`concurrenthashmap`的静态工厂方法获取一个线程安全的视图,利用其内部的分段cas操作来保证高并发下的写入性能,同时保持与标准`set`接口一致的读取行为。这种实现避免了全局锁竞争,显著提升了吞吐量。

为什么传统同步集合不适合高并发写入
传统使用`Collections.synchronizedSet(new HashSet())`包装的集合,在每次写入时都会获取全局监视器锁。当多个线程同时尝试添加元素时,它们会相互阻塞,导致CPU等待时间增加,吞吐量急剧下降。相比之下,基于`ConcurrentHashMap`的实现通过细粒度的锁机制或无锁算法(如CAS),允许不同桶(bucket)之间的写入操作并行执行,从而有效缓解瓶颈。

import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public class HighWriteDemo {
public static void main(String[] args) {
// 创建支持并发的Set
Set<String> concurrentSet = ConcurrentHashMap.newKeySet();
// 模拟多线程写入
Thread writer1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
concurrentSet.add("item-" + i);
}
});
Thread writer2 = new Thread(() -> {
for (int i = 1000; i < 2000; i++) {
concurrentSet.add("item-" + i);
}
});
writer1.start();
writer2.start();
try {
writer1.join();
writer2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Total size: " + concurrentSet.size());
}
}
上述代码展示了如何使用`ConcurrentHashMap.newKeySet()`构建一个线程安全的集合。两个线程分别向集合中添加不重叠的数据段,最终集合大小应为2000。该实现内部委托给`ConcurrentHashMap`的`putIfAbsent`方法,确保原子性且无需外部同步块。
立即学习“Java免费学习笔记(深入)”;
Java开发手册规约集合,基于阿里巴巴Java开发手册(嵩山版)。 涵盖7大维度:编程规约、异常日志、单元测试、安全规约、MySQL数据库、工程结构、设计规约。
读写一致性模型与迭代器行为差异
虽然`ConcurrentHashMap.newKeySet()`提供了高并发写入能力,但其读取行为与传统`HashSet`存在细微差别。它采用弱一致性迭代器,这意味着迭代过程中如果集合被修改,迭代器不会抛出`ConcurrentModificationException`,而是可能反映部分更新状态。对于“写多读少”场景,如果读取操作主要用于统计数量或检查存在性,这种弱一致性是可以接受的;但如果需要强一致性快照,则需额外处理。

import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
public class IteratorBehaviorDemo {
public static void main(String[] args) {
Set<String> set = ConcurrentHashMap.newKeySet();
set.add("A");
set.add("B");
Iterator<String> it = set.iterator();
while (it.hasNext()) {
String item = it.next();
System.out.println("Read: " + item);
// 在迭代期间修改集合
if (item.equals("A")) {
set.add("C");
}
}
// 输出可能包含或不包含"C",但绝不会抛异常
}
}
此示例演示了迭代过程中的并发修改行为。程序运行后,控制台将打印出读取到的元素,即使中间插入了新元素,也不会中断迭代。这验证了弱一致性特性,适合对实时性要求不高但追求吞吐量的场景。
内存占用与扩容策略对写入的影响
在高写入频率下,`ConcurrentHashMap`的扩容机制也会影响性能。默认初始容量为16,负载因子0.75。当写入速度快于GC回收速度时,频繁扩容可能导致停顿。建议根据预估数据量设置初始容量和并发级别,减少动态调整开销。此外,由于每个节点对象包含额外的元数据,内存开销略高于普通`HashSet`,但在现代JVM中通常可忽略不计。

















