【问题标题】:Is it safe to use HashSet as a very simple cache in a multi-threaded environment?在多线程环境中使用 HashSet 作为一个非常简单的缓存是否安全?
【发布时间】:2019-10-14 10:09:36
【问题描述】:

我意识到对此有类似的问题/答案,但我似乎无法准确找到我正在寻找的内容。

我正在寻求实现一个内存缓存,用于缓存对数据库的调用结果,该数据库正在执行存在性检查。这种存在性检查非常昂贵,一旦对象存在于数据库中,它将永远不会被删除,因此我只需要一个非常简单的内存缓存(甚至是进程内缓存)。一旦进行 DB 调用,该进程就会记住该 ID 的存在性检查结果,并且不应再次调用 DB。

(也许要提到的另一件事是,如果数据库中不存在该对象,则会创建它)。

我为此使用 HashSet (java),并在检查/创建完成时将 ID 添加到集合中,但是这是一个高度并发的环境,我不确定 HashSet 缺乏的影响-线程安全。

代码只使用 add() 和 contains() 方法(没有迭代)。

我并不真正关心这里和那里的缓存未命中(以及由此产生的额外数据库调用),但我想知道的是,这种 add() 和 contains() 模式是否在集合上同时被调用线程可能会导致更多的灾难性错误。

【问题讨论】:

  • 不,这不安全。您同时读取和写入非线程安全集合。那永远不安全。
  • 你也可以使用ehCache库。
  • 出于好奇,在这种特殊情况下我们会看到什么样的错误? NPE之类的?

标签: java concurrency hashmap hashset


【解决方案1】:

没有。如果要在多线程环境中使用Map,请使用Collections.synchronizedMap(<map object>)ConcurrentHashMap.newKeySet();

Set<String> concurrentSet = Collections.synchronizedSet(new HashSet<>());

或者...

Set<String> concurrentSet = ConcurrentHashMap.newKeySet();

【讨论】:

    【解决方案2】:

    您可以使用 ConcurrentHashMap 进行多线程访问和写入操作。如果你只想要HashSet,你可以从ConcurrentHashMap派生ConcurrentHashSet。你可以这样使用。

    Set<String> myConcurrentSet = ConcurrentHashMap.newKeySet();
    

    【讨论】:

    • 这对于 Java 8+ 是正确的。在 Java 8 之前:Collections.newSetFromMap(map)
    • 如果所有操作都是同步的,我担心性能,但从一些阅读来看,至少对于读取来说,没有锁定。这里有任何性能问题吗?
    • ConcurrentHashMap 具有高度可扩展性,我们不必担心性能。
    • 这是一个很好的解决方案。 CHM 适用于细分市场。所以性能随时会更好
    猜你喜欢
    • 2012-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多