为什么 ConcurrentHashMap.putifAbsent 是安全的?

发布于 2024-11-06 23:18:57 字数 397 浏览 4 评论 0原文

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

例如...

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

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

I have been reading for concurency since yesterday and i dont know much things... However some things are starting to getting clear...
I understand why double check locking isnt safe (i wonder what is the propability the rare condition to occur) but volatile fixes the issue in 1.5 +....
But i wonder if this occurs with putifAbsent

like...

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

Then does this ensures that myObj would be 100% intialiased when another thread does a cHashM.get() ??? Because it could have a reference isnt completely initialised (the double check lock problem)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

感情旳空白 2024-11-13 23:18:57

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

现在您可能会浏览代码并注意到 get 方法没有获得相同的锁。因此,您可以说可能存在过时的读物,但这也不是事实。这里的原因是条目本身的值是不稳定的。因此,您一定会获得最新的阅读内容。

If you invoke concurrentHashMap.get(key) and it returns an object, that object is guaranteed to be fully initialized. Each put (or putIfAbsent) will obtain a bucket specific lock and will append the element to the bucket's entries.

Now you may go through the code and notice that the get method doesnt obtain this same lock. So you can argue that there can be an out of date read, that isn't true either. The reason here is that value within the entry itself is volatile. So you will be sure to get the most up to date read.

世俗缘 2024-11-13 23:18:57

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

putIfAbsent method in ConcurrentHashMap is check-if-absent-then-set method. It's an atomic operation. But to answer the following part: "Then does this ensures that myObj would be 100% intialiased when another thread does a cHashM.get() ", it would depend on when the object is put into the HashMap. Usually there is a happens-before precedence, i.e., if the caller gets first before the object is placed in the map, then null would be returned, else the value would be returned.

如果没有 2024-11-13 23:18:57

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

内存一致性影响:与
其他并发集合、操作
在放置对象之前在线程中
作为键或值放入 ConcurrentMap
发生在以下动作之后
访问或删除该对象
来自另一个中的 ConcurrentMap
线程。

-- java.util.ConcurrentMap< /code>

所以,是的,你有你的发生在关系。

The relevant part of the documentation is this:

Memory consistency effects: As with
other concurrent collections, actions
in a thread prior to placing an object
into a ConcurrentMap as a key or value
happen-before actions subsequent to
the access or removal of that object
from the ConcurrentMap in another
thread.

-- java.util.ConcurrentMap

So, yes you have your happens-before relationship.

玩套路吗 2024-11-13 23:18:57

我不是这方面的专家,但是查看 ConcurrentHashMapSegment 的实现,我发现 volatile 字段 count< /code> 似乎用于确保线程之间的适当可见性。所有读取操作都必须读取 count 字段,所有写入操作都必须写入该字段。来自课堂上的评论:

Read operations can thus proceed without locking, but rely
on selected uses of volatiles to ensure that completed
write operations performed by other threads are
noticed. For most purposes, the "count" field, tracking the
number of elements, serves as that volatile variable
ensuring visibility.  This is convenient because this field
needs to be read in many read operations anyway:

   - All (unsynchronized) read operations must first read the
     "count" field, and should not look at table entries if
     it is 0.

   - All (synchronized) write operations should write to
     the "count" field after structurally changing any bin.
     The operations must not take any action that could even
     momentarily cause a concurrent read operation to see
     inconsistent data. This is made easier by the nature of
     the read operations in Map. For example, no operation
     can reveal that the table has grown but the threshold
     has not yet been updated, so there are no atomicity
     requirements for this with respect to reads.

I'm not an expert on this, but looking at the implementation of Segment in ConcurrentHashMap I see that the volatile field count appears to be used to ensure proper visibility between threads. All read operations have to read the count field and all write operations have to write to it. From comments in the class:

Read operations can thus proceed without locking, but rely
on selected uses of volatiles to ensure that completed
write operations performed by other threads are
noticed. For most purposes, the "count" field, tracking the
number of elements, serves as that volatile variable
ensuring visibility.  This is convenient because this field
needs to be read in many read operations anyway:

   - All (unsynchronized) read operations must first read the
     "count" field, and should not look at table entries if
     it is 0.

   - All (synchronized) write operations should write to
     the "count" field after structurally changing any bin.
     The operations must not take any action that could even
     momentarily cause a concurrent read operation to see
     inconsistent data. This is made easier by the nature of
     the read operations in Map. For example, no operation
     can reveal that the table has grown but the threshold
     has not yet been updated, so there are no atomicity
     requirements for this with respect to reads.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文