【问题标题】:Thread safe data structure to check for existence and write if not线程安全的数据结构,用于检查是否存在,如果不存在则写入
【发布时间】:2018-06-23 14:37:07
【问题描述】:

我想解析一长串带有重复项的字符串,并将每个唯一的字符串保存到一个数组中一次。在多线程方法中,线程将检查共享数据结构是否存在,如果不存在则写入。

我忘记了适合这个的数据结构。 Java.util 中的任何东西都可以,高性能的第三方库也可以。

【问题讨论】:

  • 使用 ConcurrentHashMap 但如果您的字符串都相对较短(我会说少于 100 个字符),这不太可能给您带来明显的性能提升 - 它甚至可能比单线程实现。

标签: java concurrency java.util.concurrent


【解决方案1】:

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
    }
}

【讨论】:

  • “它看起来像这样”希望不会。 ConcurrentHashSet 并不神奇:它不知道对其进行的单独调用应该以原子方式执行(特别是:像这样使用containsadd 是行不通的)。相反,使用if (!seenStrings.add(aString)),并删除else
  • 你在用 PRESENT 对象做什么?如果我们不得不做这个额外的步骤只是为了使用一个 Map,那么不同的数据结构不是更合适吗?
【解决方案2】:

您可以为此使用CopyOnWriteArrayListConcurrentLinkedQueue。但是,如果您有很多写入 CopyOnWrite 方法将是昂贵的。

如果您想删除重复项,请考虑使用CopyOnWriteArraySet

【讨论】:

  • 使用链表删除重复项实际上是(是的,我的意思是实际上不是)最糟糕的实现。
  • 从未提及删除重复项。
猜你喜欢
  • 2017-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-05
  • 2016-01-06
  • 1970-01-01
  • 2023-03-15
  • 1970-01-01
相关资源
最近更新 更多