构造函数中的两个"volatile"变量遵循"发生前"关系?



下面是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的线程将永远不会将value视为null ?

在给出的构造函数代码中,对value的赋值总是被视为发生在对next的赋值之前。但是,在对并发代码中的不变量进行推理时,必须非常小心。可能有其他线程并发地执行分配给value的其他代码。由于您的问题已经假设实例被发布到其他线程,因此几乎不可能确保没有其他编写器。

最后,请注意,在给定代码的情况下,value实际上可能一开始就被分配为null

引自Atomic Access:

使用易失性变量降低了内存一致性错误的风险,因为任何对易失性变量的写入与后续相同变量的读取建立了happens-before关系。这意味着对volatile变量的更改对于其他线程总是可见的。更重要的是,这也意味着当一个线程读取一个易失性变量时,它不仅看到对易失性变量的最新更改,还看到导致更改的代码的副作用。

可以看到,happens-before relationship是针对相同的变量。

谢谢@JBNizet的提醒。

next的"副作用"可以是分配给value的代码。但它只是意味着线程将看到value,不保证其他线程不会将value设置为其他值,包括null

考虑如何调用构造函数:

myHashEntry = new HashEntry(hash, key, value, next);
直到构造函数运行完成后才设置myHashEntry。在构造函数仍在运行时,没有其他可用的对象引用。因此,其他线程无法并发地查看部分构造的对象。

相关内容

  • 没有找到相关文章

最新更新