10

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

像...

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

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

4

4 回答 4

5

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

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

于 2011-05-13T20:28:37.990 回答
5

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

于 2011-05-13T20:29:57.330 回答
2

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

内存一致性效果:与其他并发集合一样,线程中的操作在将对象作为键或值放入 ConcurrentMap 之前发生在另一个线程中从 ConcurrentMap 访问或删除该对象之后的操作。

--java.util.ConcurrentMap

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

于 2011-05-13T21:01:41.793 回答
1

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

因此,读取操作可以在没有锁定的情况下进行,但依赖
关于挥发物的选定用途,以确保完成
其他线程执行的写操作是
注意到。对于大多数目的,“计数”字段,跟踪
元素的数量,用作该易失性变量
确保可见性。这很方便,因为这个字段
无论如何都需要在许多读取操作中读取:

   - 所有(非同步的)读取操作必须首先读取
     "count" 字段,并且不应该查看表条目,如果
     它是 0。

   - 所有(同步的)写操作都应该写到
     在结构上更改任何 bin 后的“计数”字段。
     操作不得采取任何行动,甚至可能
     暂时导致并发读取操作看到
     不一致的数据。这更容易通过性质
     Map中的读操作。例如,无操作
     可以显示该表已增长但阈值
     还没有更新,所以没有原子性
     关于读取的要求。
于 2011-05-13T20:27:19.823 回答