【问题标题】:Why ConcurrentHashMap.putifAbsent is safe?为什么 ConcurrentHashMap.putifAbsent 是安全的?
【发布时间】:2011-05-13 20:13:08
【问题描述】:

从昨天开始我一直在阅读并发性,我不太了解......但是有些事情开始变得清晰......
我理解为什么双重检查锁定不安全(我想知道这种罕见情况发生的可能性是多少)但是 volatile 在 1.5 + 中修复了这个问题......
但我想知道putifAbsent 是否会发生这种情况

喜欢...

myObj = new myObject("CodeMonkey");
cHashM.putIfAbsent("keyy",myObj);  

那么,当另一个线程执行cHashM.get() 时,这是否确保myObj 100% 初始化?因为它可能有一个引用没有完全初始化(双重检查锁定问题)

【问题讨论】:

    标签: java concurrency concurrenthashmap


    【解决方案1】:

    如果您调用concurrentHashMap.get(key) 并返回一个对象,则该对象保证被完全初始化。每个 put(或 putIfAbsent)都将获得一个特定于存储桶的锁,并将元素附加到存储桶的条目中。

    现在您可能会查看代码并注意到 get 方法没有获得相同的锁。所以你可以争辩说可能有过时的阅读,这也不是真的。这里的原因是条目本身的值是不稳定的。所以你一定会得到最新的阅读。

    【讨论】:

    • 所以如果我理解正确没有问题,就像在经典的双重检查锁定范例中一样?
    • @Parhs:对,没问题。
    • 你是对的。实际上,您在问题中自己回答了“但 volatile 在 1.5 + 中修复了问题” 由于从 CCHM 返回的值是一个 volatile 值,因此它也可以避免部分初始化。
    • @JohnVint 我有一个类似的问题here 在 CHM 上以原子方式执行 get 和 put 操作。你能帮我在那边吗?
    • @david 我在那里回答了你的问题。唯一需要 check-then-set 逻辑的情况是它是否需要被记忆。
    【解决方案2】:

    ConcurrentHashMap 中的putIfAbsent 方法是 check-if-absent-then-set 方法。这是一个原子操作。但是要回答以下部分:“那么这样做是否可以确保 myObj 在另一个线程执行 cHashM.get() 时被 100% 初始化”,这取决于对象何时放入 HashMap。通常有一个happens-before优先级,即如果调用者在对象被放入映射之前先获得,则返回null,否则返回值。

    【讨论】:

    • null 要返回的不是prb,而是对非完全构造初始化对象的引用。 (双重检查锁定的问题)
    • +1 Upvoted for "Atomic" Atomic 负责线程的排序,因此 .put() 方法不会被调用两次 ConcurrentHashMap 负责 Writer .put() 方法线程的同步
    【解决方案3】:

    文档的相关部分是这样的:

    内存一致性效果:与 其他并发集合、动作 在放置对象之前在线程中 进入 ConcurrentMap 作为键或值 发生之前的动作 访问或移除该对象 来自另一个中的 ConcurrentMap 线程。

    -- java.util.ConcurrentMap

    所以,是的,您有 happens-before 关系。

    【讨论】:

      【解决方案4】:

      我不是这方面的专家,但是查看ConcurrentHashMapSegment 的实现,我发现volatile 字段count 似乎用于确保线程之间的适当可见性。所有读取操作都必须读取count 字段,并且所有写入操作都必须写入它。来自班级的cmets:

      因此,读取操作可以在没有锁定的情况下进行,但依赖 关于挥发物的选定用途,以确保完成 其他线程执行的写操作是 注意到。对于大多数目的,“计数”字段,跟踪 元素的数量,用作该易失性变量 确保可见性。这很方便,因为这个字段 无论如何都需要在许多读取操作中读取: - 所有(非同步的)读取操作必须首先读取 "count" 字段,并且不应该查看表条目,如果 它是 0。 - 所有(同步的)写操作都应该写到 在结构上更改任何 bin 后的“计数”字段。 操作不得采取任何行动,甚至可能 暂时导致并发读取操作看到 不一致的数据。这更容易通过性质 Map中的读操作。例如,无操作 可以显示该表已增长但阈值 还没有更新,所以没有原子性 关于读取的要求。

      【讨论】:

        猜你喜欢
        • 2014-09-22
        • 1970-01-01
        • 2017-04-07
        • 2023-03-30
        • 2019-10-27
        • 2023-03-28
        • 2011-08-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多