当只有一个编写器和N个读卡器时,这种情况是不是需要锁定?

时间:2013-08-04 13:16:17

标签: java multithreading collections

HashMap不是线程安全的。

在我的情况下:1个作者线程更新HashMapN读者线程以从HashMap读取。

我发现只有一个不好的案例:

  1. 读者N读取值V1
  2. 编写器更新V1到V2
  3. 读者N使用值V1(但现在是V2)
  4. 如果在我的事业中,我们可以容忍这种情况,还有其他不好的情况吗?

5 个答案:

答案 0 :(得分:4)

如果读者将遍历HashMap并且同时它将被作者修改,则可能发生更严重的问题。通常,修改此类集合(使用其他语言,如C#或Python)会使其所有迭代器失效。

来自documentation

  

请注意,此实现未同步。 如果多个线程同时访问哈希映射,并且至少有一个线程在结构上修改了映射,则必须在外部进行同步。 (结构修改是添加或删除一个或多个映射的任何操作;仅更改与实例已包含的键关联的值不是结构修改。)

答案 1 :(得分:1)

你提到的案例并不是真正的问题,因为如果HashMap是线程安全的,那么同样的事情就会发生。你可能遇到麻烦的地方是,当V1正在进行更改时,V2从HashMap读取。那时,HashMap的内部状态不一致。这可能导致V2的程序神秘地崩溃,没有明显的理由。

答案 2 :(得分:1)

没有正确同步,有两个问题。一个是visibility and原子性。 假设您有映射,并且在一个线程中您正在递增该值。可能其他线程可能会看到陈旧的值。类似地,如果一个线程已经放置了K,V,则其他线程可能无法看到它。同样,迭代也会受到影响。

因此对于safe publicationvisibility问题更好地使用ConcurrentHashMap,它使用lock striping来获得更好的并发性。但是对于我上面提到的增量内容,我们需要使用外部同步。

如果我们不更改value(K)key (K)并且我们只是插入/来自HashMap,那么我们可以做的最好的事情是将密钥和值类设为{{ 1}}类。并且重要的是将immutable声明为HashMap。这将处理final关系,问题将消失。感谢。

答案 3 :(得分:0)

当读者在其中搜索时,编写者可以修改HashMap的内部结构,从而导致随机行为(错误的值,null而不是值,异常)。此外,更改可能永远不会传播到其他线程而没有任何告诉jvm期望多线程访问,更新永远不会在多个CPU内核上同步,或者jvm只是将它们优化为noop。

在您的情况下,您可以使用ReadWriteLock确保所有读者可以在作者具有独占访问权的同时访问地图。

答案 4 :(得分:0)

好吧,如果你问的是在这种情况下会发生什么,那么我们应该首先理解的是,当一个类被记录为NOT THREAD SAFE时,那么所有那些不好的事情都会发生,这通常发生在非线程安全的情况下类。现在非线程安全类会发生什么,根据它的合同,它将无法正常运行。这意味着如果你调用get(Key),它可能不会返回正确的值。非线程安全类的这种行为归因于ATOMICITY和VISIBILTY。

最重要的是,如果一个类不是线程安全的,那么你就不能指望它的合同或暴露的功能。