以下是Java7中ConcurrentHashMap
的示例:
static final class HashEntry<K,V> {
final int hash;
final K key;
volatile V value;
volatile HashEntry<K,V> next;
HashEntry(int hash, K key, V value, HashEntry<K,V> next) {
this.hash = hash;
this.key = key;
this.value = value;
this.next = next;
}
因此,如果某个帖子看到next
字段,是否可以保证value
字段不是null
?
更新:
因此,如果我在测试中限制value
在初始化后无法修改,并且构造函数无法分配null
值,则next
获取HashEntry
的线程1}}永远不会将value
视为null
?
答案 0 :(得分:1)
在提供的构造函数代码中,value
的分配将始终被视为在分配给next
之前发生。但是,在推断并发代码中的不变量时,您必须非常小心。可能有其他线程同时执行分配给value
的其他代码。由于您的问题已经假定实例已发布到其他线程,因此几乎不可能确保没有其他编写者。
最后,请注意,鉴于提供的代码,value
实际上可能会在开始时分配null
。
答案 1 :(得分:0)
引自Atomic Access(突出显示是我的):
使用volatile变量可以降低内存一致性错误的风险,因为任何写入到volatile变量都会建立与之后的读取之前发生的关系相同变量即可。这意味着对volatile变量的更改始终对其他线程可见。更重要的是,它还意味着当线程读取volatile变量时,它不仅会看到volatile的最新更改,还会看到导致更改的代码的副作用。
如您所见,happens-before relationship
用于同一变量。
感谢@ JBNizet的提醒。
next
的“副作用”可以是分配给value
的代码。但这只是意味着线程会看到value
不保证其他线程不会将value
设置为其他值,包括null
。
答案 2 :(得分:0)
考虑如何调用构造函数:
myHashEntry = new HashEntry(hash, key, value, next);
在构造函数运行完成之前,不会设置myHashEntry。在构造函数仍在运行时,没有其他可用对象的引用。因此,另一个线程无法同时查看部分构造的对象。