Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中final和volatile字段在内存模型语义上的差异_Java_Multithreading_Concurrency_Thread Safety_Volatile - Fatal编程技术网

Java中final和volatile字段在内存模型语义上的差异

Java中final和volatile字段在内存模型语义上的差异,java,multithreading,concurrency,thread-safety,volatile,Java,Multithreading,Concurrency,Thread Safety,Volatile,从实践中的Java并发性: 当一个字段被声明为volatile时,编译器和运行时被打开 注意,这个变量是共享的,对它的操作应该 不能与其他内存操作一起重新排序。可变变量是 不缓存在寄存器或缓存中,在这些寄存器或缓存中它们对其他对象隐藏 处理器,因此读取易失性变量总是返回最多 任何线程最近的写入。(p25) 以及 无法修改最终字段(尽管它们引用的对象可以 如果它们是可变的,则可以修改),但它们也有特殊的语义 在Java内存模型下。正是使用final字段使 可能的初始化安全保证(见第3.5.2节)

从实践中的Java并发性:

当一个字段被声明为volatile时,编译器和运行时被打开 注意,这个变量是共享的,对它的操作应该 不能与其他内存操作一起重新排序。可变变量是 不缓存在寄存器或缓存中,在这些寄存器或缓存中它们对其他对象隐藏 处理器,因此读取易失性变量总是返回最多 任何线程最近的写入。(p25)

以及

无法修改最终字段(尽管它们引用的对象可以 如果它们是可变的,则可以修改),但它们也有特殊的语义 在Java内存模型下。正是使用final字段使 可能的初始化安全保证(见第3.5.2节) 这使得不可变对象可以自由访问和共享,而无需 同步(第32页)

背诵不安全出版物:

public class Holder {
      private int n;
      public Holder(int n) { this.n = n; }
      public void assertSanity() {
         if (n != n) // might be true for other threads.
     }
}
令人惊讶的是,
n
的值可能会被其他线程视为过时。但是,
final
修饰符会起作用。类似于volatile,不是吗?
final
字段是否本质上是易变的?(不允许使用
final volatile
的可能解释)

这是否可能是不允许使用私有volatile的原因

允许使用私有易失性

你是说
最终挥发性
?是的,这些修饰符在性质上是不兼容的-
final
var,其值/引用不能更改,不需要额外的
volatile
goodies(以及相关的开销),因为
final
字段的变异是不可能的,并且跨多个线程的读取是一致的

但是
JMM
确实为
final
字段提供了初始化易失性样式一致性。AFAIK它是在
JSR133
中实现的(包含在
JavaSE5.0
中)。在此之前,
JSR
init读取在数据竞争期间可能不一致(例如返回null或某个中间值)

PS:我找到了与您的问题有关的问题。强烈推荐(以及第二部分)

这是否可能是不允许使用私有volatile的原因

允许使用私有易失性

你是说
最终挥发性
?是的,这些修饰符在性质上是不兼容的-
final
var,其值/引用不能更改,不需要额外的
volatile
goodies(以及相关的开销),因为
final
字段的变异是不可能的,并且跨多个线程的读取是一致的

但是
JMM
确实为
final
字段提供了初始化易失性样式一致性。AFAIK它是在
JSR133
中实现的(包含在
JavaSE5.0
中)。在此之前,
JSR
init读取在数据竞争期间可能不一致(例如返回null或某个中间值)


PS:我找到了与您的问题有关的问题。强烈推荐它(以及第二部分)

volatile
仅与变量本身的修改相关,而与它所指的对象无关。使用
final volatile
字段没有任何意义,因为无法修改
final
字段。只需声明字段
final
,它就应该可以了。

volatile
只与变量本身的修改相关,而与它引用的对象无关。使用
final volatile
字段没有任何意义,因为无法修改
final
字段。只需声明字段
final
,就可以了。

不,
final
字段本质上不是易变的

如果是的话,那将是不必要的昂贵,因为在大多数情况下,您需要在
volatile
写入之后设置一个StoreLoad屏障

这对于
final
字段是可以避免的,因为您有一个额外的约束可以帮助您-您知道
final
字段必须在相应的类或实例对象完全初始化时初始化

该规范可能有点难以阅读(查看JLS),但请记住,与臭名昭著的JMM因果关系部分一样,主要内容是正式描述大多数人的直觉行为

至于实施,通常需要两件事:

  • 确保
    final
    字段存储,包括链下游的存储(如果字段是引用),不能使用构造函数之外的存储重新排序。如果底层硬件体系结构具有强大的内存模型(如x86),即使您内联了构造函数,这通常也是不可操作的

  • 确保给定线程中的第一个
    final
    字段加载不能与该字段所属的相应引用的同一线程中的第一个加载一起重新排序。这几乎总是不可操作的,因为所有编译器和大多数硬件架构都遵循负载依赖性

  • 最后,在大多数体系结构上成本低得多的LoadStore和StoreStoreStore屏障应该足以实现
    final
    字段

    ===

    您可以在以下章节中阅读更多关于如何实现
    final
    字段的信息:

    • Doug Lea(参见最终字段部分)
    • Alexey Shipilev的精彩博客文章
    ===


    注意:即使存在
    final
    字段,不安全的发布也是危险的。请参阅以了解一些注意事项。

    否,
    final
    字段本质上不是易变的

    如果是的话,那将是不必要的昂贵,因为在大多数情况下,您需要在
    volatile
    写入之后设置一个StoreLoad屏障

    对于
    final
    字段,这是可以避免的,因为