3

我想将预先构建的 Map 传递给多个线程,这些线程只会同时从 Map 中读取值。在这种情况下,我是否需要担心并发访问并使用 ConcurrentHashMap 而不是 HashMap?

4

7 回答 7

6

您仍然需要确保在创建和初始化 Map 的线程与随后读取它的线程之间存在“happens-before”关系。如果没有这样的关系,理论上读线程有可能看到陈旧的数据。

如果您在启动其他线程的线程中创建并填充 Map ......在它执行此操作之前......你应该没问题。

确保安全的另一种简单方法是执行以下操作:

public class Foo {
    private final Map map;

    public Foo(....) {
        map = new HashMap();
        // populate
    }

    public Map getMap() {
        // If the 'map' is final, and nothing changes it apart from 
        // the constructor, this method doesn't need to be synchronized.
    }

这两者都会导致创建/初始化和每个线程第一次使用 Map 之间的“先发生”关系。

您也可以map在上面声明为volatile,但可能会导致比严格需要的更多的缓存刷新;即你会受到小的性能影响。

于 2012-07-02T11:31:39.867 回答
3

此外,为了确保仅针对读取操作进行处理,您可以做的是返回Collections.unmodifiableMap(Map)

于 2012-07-02T11:31:26.247 回答
2

理论上,并发读取不应该对集合造成问题。

但是如果你修改一次,很容易出错,那么你应该使用并发版本。

于 2012-07-02T11:26:05.523 回答
2

如果所有线程都在读取它,则传递 HashMap 是安全的。但是,在传递地图之前,我会调用 Collections.unmodifiableMap() 以确保如果其中一个线程意外修改它,因为将来某些程序员不尊重当前的合同,你会得到一个例外。

于 2012-07-02T11:29:37.233 回答
2

你总是需要担心线程安全。在您的具体示例中,如果您

  1. 在单个线程中完全构建地图;
  2. volatile通过设置一个变量来引用它,将它发布到其他线程。

或者,如果这是一个选项,请确保在映射准备好之前不启动线程。

于 2012-07-02T11:33:31.127 回答
1

,您不必担心。
除非有人在线程访问它时更改预建地图。

于 2012-07-02T11:26:19.653 回答
1

不,你不需要使用它。仅在以下情况下会产生冲突:

  • 当一些线程可能会读取数据,而其他线程可能会尝试覆盖它。
  • 第二个是当每个线程都尝试更新数据时。

当每个线程仅尝试读取值时,不会产生冲突。

于 2012-07-02T11:30:20.403 回答