【问题标题】:Is this case not need to lock when there are only 1 writer and N reader?当只有1个写者和N个读者时,这种情况不需要锁定吗?
【发布时间】:2013-08-04 13:16:16
【问题描述】:

HashMap 不是线程安全的。

在我的例子中:1 个写入线程更新HashMapN 读取线程读取HashMap

我发现只有 1 个坏案例:

  1. 读卡器 N 读到一个值 V1
  2. 编写器将 V1 更新到 V2
  3. reader N使用值V1(但现在是V2)

如果在我的业务中,我们可以容忍这种情况,还有其他不好的情况吗?

【问题讨论】:

  • 您需要这些用例的用例或解决方案吗?

标签: java multithreading collections


【解决方案1】:

如果读取器将遍历HashMap 并同时被写入器修改,则可能会出现更严重的问题。通常修改此类集合(在 C# 或 Python 等其他语言中)会使其所有迭代器无效。

来自documentation

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

【讨论】:

    【解决方案2】:

    您提到的情况并不是真正的问题,因为如果 HashMap 是线程安全的,则可能会发生同样的事情。如果 V2 在 V1 正在进行更改时从 HashMap 读取数据,则可能会遇到麻烦。此时HashMap的内部状态是不一致的。这可能会导致 V2 的程序在没有明显原因的情况下神秘地崩溃。

    【讨论】:

      【解决方案3】:

      没有正确同步有两个问题。一个是visibility andatomicity`。 假设您有地图,并且在一个线程中增加了值。比其他线程可能会看到一个陈旧的值。类似地,如果一个线程已经放置了 K、V,那么另一个线程可能看不到它。同样,迭代也会受到影响。

      所以对于 safe publication , visibility 问题最好使用 ConcurrentHashMap ,它使用 lock striping 以获得更好的并发性。但是对于我上面提到的增量内容,我们需要使用外部同步。

      如果我们不更改value(K)key (K) 并且我们只是从HashMap 插入/getting 然后将键和值类设为immutable 类,我们可以做的最好的事情。重要的是,将HashMap 声明为final。这将处理happens before 关系并且问题将消失。谢谢。

      【讨论】:

        【解决方案4】:

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

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

        【讨论】:

          【解决方案5】:

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

          底线是,如果一个类不是线程安全的,你就不能指望它的契约或暴露的特性。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-10-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-12-14
            相关资源
            最近更新 更多