Java的final关键字的内存语义

概念介绍:

1.内存屏障:

内存屏障(Memory Barier,或者有时叫做内存栅栏,Memory Fence)是一种CPU指令,用于控制特定条件下的重排序和内存可见性问题。Java编译期也会根据内存屏障的规则禁止重排序。
内存屏障可以分为以下几种类型:

  • LoadLoad屏障:Load1;LoadLoad;Load2,在Load2及后续读取操作要读取的数据被访问强,保证Load1要读取的数据被读取完毕。
  • StoreStore屏障:Store1;StoreStore;Store2;在Store2及其后续的写入操作执行前,保证Store1的写入操作对其他的处理器可见。
  • LoadStore屏障:Load1;LoadStore;Store2;在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕。
  • StoreLoad屏障:Store1;StoreLoad;Load2;在Load2及其后续的读取操作被执行前,保证Store1的写入对所有处理器可见。它的开销是四种屏障中最大的。 在大多数处理器的实现中,这个屏障是个万能屏障,兼具其他三种内存屏障的功能。

对于Final域,编译器和处理器要遵守两个重排序规则:

  1. 在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序。
  2. 初次读一个包含final域的对象的引用,与随后初次读这个final域,这两个操作之间不能重排序。

写final域的重排序规则

写final域的重排序规则禁止把final域的写重排序到构造函数之外。这个规则的实现包含2个方面:

  • JMM禁止编译器把final域的写重排序到构造函数之外
  • 编译器会在final域的写之后,构造函数return之前,插入一个StoreStore屏障。这个屏障禁止处理器把final域的写重排序到构造函数之外。

写final域的重排序规则可以确保:在对象引用为任何线程可见之前,对象的final域已经被正确初始化过了,而普通域不具有这个保障。

读final域的重排序规则

读final域的重排序规则如下:

  • 在一个线程中,初次读对象引用与初次读改对象包含的final域,JMM禁止处理器重排序这两个操作(仅仅针对处理器)。编译器会在读final域操作的前面插入一个LoadLoad屏障。

读final域的重排序可以确保:在读一个对象的final域之前,一定会先读包含这个final域的对象引用。

推荐阅读更多精彩内容

  • 此文为转载: 转载地址放在链接中:原文发表地址 整理 by 微凉季节 评价:从多线程引出处理器内存,再杀到总线仲裁...
    topwqp阅读 2,727评论 0 62
  • 目录: 1. 指令重排 2. 顺序一致性 3. volatile 4. final 1.指令重排 要了解指令重排,...
    西部小笼包阅读 142评论 0 1
  • pdf下载地址:Java面试宝典 第一章内容介绍 20 第二章JavaSE基础 21 一、Java面向对象 21 ...
    王震阳阅读 73,636评论 25 504
  • 1. final的简介 final可以修饰变量,方法和类,用于表示所修饰的内容一旦赋值之后就不会再被改变,比如St...
    小陈阿飞阅读 894评论 1 5
  • 第2章 java并发机制的底层实现原理 Java中所使用的并发机制依赖于JVM的实现和CPU的指令。 2.1 vo...
    kennethan阅读 210评论 0 1