如果我只是从集合中读取,我是否需要担心线程安全?

时间:2012-07-02 11:24:31

标签: java concurrency

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

7 个答案:

答案 0 :(得分:6)

您仍然需要确保创建和初始化Map的线程与随后读取它的线程之间存在“before-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之间的“先发生”关系。

你也可以在上面声明mapvolatile,但可能会导致更多的缓存刷新而不是严格需要发生;也就是说你会受到很小的打击。

答案 1 :(得分:3)

另外,为了确保仅为阅读操作处理,您可以做的是返回Collections.unmodifiableMap(Map)

答案 2 :(得分:2)

理论上,并发阅读不应该导致收藏问题。

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

答案 3 :(得分:2)

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

答案 4 :(得分:2)

您始终需要担心线程安全问题。在您的具体示例中,如果您

就足够了
  1. 在一个线程中完全构建地图;
  2. 通过设置volatile变量来引用它来将其发布到其他线程。
  3. 或者,如果这是一个选项,请确保在地图准备好之前不会启动线程。

答案 5 :(得分:1)

,你不必担心。
除非有人在线程访问时更改预先构建的地图。

答案 6 :(得分:1)

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

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

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