java.util 包中的集合类不是线程安全的,以便在单线程应用程序中提供最大性能。 (Vector 和 Hashtable 除外)
有几种方法可以实现您正在寻找的线程安全。
同步包装器
Set<String> safeSet = Collections.synchronizedSet(new HashSet<>());
这会将所有对底层集合的调用包装在一个同步块中,锁定对象。然而,这意味着当一个线程迭代集合中的元素时,所有其他集合的方法都会阻塞,导致其他线程不得不等待。
java.util.concurrent 包
Java 5 引入了并发集合,它提供了比同步包装器更好的性能。
有不同的风格:copy-on-write、Compare-And-Swap 和并发集合。
并发集合使用比同步更灵活的特殊锁。
因此,对于您正在做的事情,如果 HashSet 是单线程的,它可能是一个很好的匹配。在并发包中,您可以使用 ConcurrentHashMap。
看起来像这样:
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
...
private static final Object PRESENT = new Object();
Map<String, Object> seenStrings = new ConcurrentHashMap<>();
for ( String aString : stringList ) {
if ( seenStrings.containsKey(aString) ) {
// Already there
} else {
// Not seen yet
seenStrings.put(aString, PRESENT);
}
}
更新
安迪的评论很好,如果您已经看过或没有看过某件物品,我不确定您想做什么。
您可以这样做以确保自动执行检查和插入
if (seenStrings.put(aString, PRESENT) == null) {
// Not seen yet
}
更新 在 Java 8+ 中,您可以创建由指定映射支持的集合。实际上是一个 ConcurrentHashSet。
Set<String> seenStrings = Collections.newSetFromMap(new ConcurrentHashMap<>());
for (String aString : stringList) {
if (seenStrings.add(aString)) {
// Not seen yet
}
}