构造函数中的两个“volatile”变量遵循Happens-before关系?

时间:2015-07-26 07:18:39

标签: java concurrency java.util.concurrent concurrenthashmap concurrent-programming

以下是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

3 个答案:

答案 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。在构造函数仍在运行时,没有其他可用对象的引用。因此,另一个线程无法同时查看部分构造的对象。