Java内存模型-final域的内存语义
一 引言
说到final你肯定知道它是Java中的关键字,那么它所在Java中的作用你知道吗?不知道的话,请前往这篇了解下https://www.cnblogs.com/yuanfy008/p/8021673.html
今天我们来说说final域在JMM中的内存语义。
二 final域的重排序规则
开门见山,对于final域,编译器和处理器一定要遵守两个重排序规则(JSR-133才增强了final域):
1)在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这个两个操作不能被重排序。
2)初次读一个包含final域的对象的引用,与随后初次读这个final域,这两个操作之间不能重排序。
下面我们通过案例来说明这两点(假设线程1执行writer(),随后另一个线程执行reader()方法):
public class FinalExample {
static volatile boolean flag = true;
int i = 0;
final int j;
static FinalExample obj; public FinalExample() { // 构造函数
i = 1; // 写普通域
j = 2; // 写final域
} public static void writer() { // 线程1写入
obj = new FinalExample();
} public static void reader() { // 线程2读取
FinalExample example = obj; // 读对象引用
System.out.println(example.i); // 读普通域
System.out.println(example.j); // 读final域
}
}
写final域的重排序规则禁止把final域的写重排序到构造函数之外。这个规则的实现包含下面两个方面:
1)JMM禁止编译器吧final域的写重排序到构造函数之外。
2)编译器会在final域的写之后,构造函数return之前,插入一个StoreStore屏障。这个屏障禁止处理器把final域的写重排序到构造函数之外。
所以线程1执行顺序如下图(其中写普通域的顺序无法保证,理论上是存在下面三种情况的,要想验证普通域是否有重排序的结果有点难,因为无法保证线程1把普通域重排序后,线程2能够读取它之前的0值):
读final域的重排序规则是:在一个线程中,初次读这个对象引用与初次读该对象包含的final域,JMM禁止处理器重排序这两个操作。其中编译器会在读final域操作的前面插入一个LoadLoad屏障。由于插入了loadLoad屏障,读普通域i的操作是不会重排序到读final域,但是不保证它会重排到读对象引用这个操作的前面。所以线程2的一个执行顺序就能想象到了,这里就不画线程2的执行顺序图了。
三 final域为引用类型
如果finaly域为引用类型,JMM中是怎么处理的呢?对于引用类型,写final域的重排序规则对编译器和处理器增加了如下约束:在构造函数内对一个final引用的对象的成员域的写入,与随后在构造函数外把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序。
以上及其以上都要注意:只针对于构造函数方法内。另外要想以上规则确保,还需要一个条件:在构造函数内部,不能让这个被构造对象的引用被其他线程可见,也就是对应引用不能再构造函数中“逸出”。如下案例:
class FinalReferenceEscapeExample {
final int i;
static FinalReferenceEscapeExample obj; public FinalReferenceEscapeExample() {
i = 1; // 1
obj = this; // 2 this引用逸出
} public static void writer() { // 线程1
new FinalReferenceEscapeExample();
} public static void reader() { // 线程2
if (obj != null) {
System.out.println(obj.i);
}
}
}
上面程序,第一步写final域与第二步是不保证重排序的。所以当第一步与第二步重排之后,线程1执行完这步(obj = this)后,时间片分给第二个线程执行,那么线程2将会获取final域初始化之前的值,这肯定就违背了程序的初衷。
Java内存模型-final域的内存语义的更多相关文章
- Java内存模型-final域的内存语义--没明白,预留以后继续理解
https://www.cnblogs.com/yuanfy008/p/9349275.html 来自 Java并发编程(1)-Java内存模型
- final域的内存语义
final 一.final的基本语义 final关键字可以用来修饰类.方法和变量(包括成员变量和局部变量) 当用final修饰一个类时,表明这个类不能被继承. 当用final修饰一个方法时,表明这个方 ...
- java内存模型7-处理器内存模型
处理器内存模型 顺序一致性内存模型是一个理论参考模型,JMM和处理器内存模型在设计时通常会把顺序一致性内存模型作为参照.JMM和处理器内存模型在设计时会对顺序一致性模型做一些放松,因为如果完全按照顺序 ...
- 深入理解 Java 内存模型(一)- 内存模型介绍
深入理解 Java 内存模型(一)- 内存模型介绍 深入理解 Java 内存模型(二)- happens-before 规则 深入理解 Java 内存模型(三)- volatile 语义 深入理解 J ...
- java线程内存模型,线程、工作内存、主内存
转自:http://rainyear.iteye.com/blog/1734311 java线程内存模型 线程.工作内存.主内存三者之间的交互关系图: key edeas 所有线程共享主内存 每个线程 ...
- Java并发编程之final域的内存语义
一.final域的重排序规则 对于final域,编译器和处理器要遵循两个重拍序规则: 1.在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序 ...
- Java并发编程原理与实战四十四:final域的内存语义
一.final域的重排序规则 对于final域,编译器和处理器要遵循两个重拍序规则: 1.在构造函数内对一个final域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序 ...
- Java内存模型(MESI、内存屏障、volatile和锁及final内存语义)
JMM (Java内存模型) Java线程的实现 实现线程主要有三种方式,Java线程从JDK1.3后采用第一种方式实现: 使用内核线程实现(1:1实现) 使用用户线程实现(1:N实现) 使用用户线程 ...
- java内存模型-final
与前面介绍的锁和 volatile 相比较,对 final 域的读和写更像是普通的变量访问.对于final 域,编译器和处理器要遵守两个重排序规则: 在构造函数内对一个 final 域的写入,与随后把 ...
随机推荐
- Beta阶段冲刺-1
1. 新成员 新加入成员,克克飞同学,任务是去弄公众号相关的部分. 队员 个人简介 博客地址 杨晨露 每天都在开会的PM http://www.cnblogs.com/ycll/ 游舒婷 每天都在装死 ...
- FPGA---Basys3(实验内容汇总贴)
前言 本博文为FPGA---Basys3入门板的实验汇总帖子. 实验指导书 实验源码github地址 实验目录 组合逻辑电路设计 编码器 比较器 全加器 时序逻辑电路设计 D 触发器的实现 同步复位的 ...
- Mysql设置允许外网访问(图文)
1.打开mysql.exe(MySQL Command Line Client),输入密码 2.输入:use mysql; 3.查询host输入: select user,host from user ...
- java使用JMail通过QQ邮件服务器实现自动发送邮件
前言:项目开发的过程中,我们项目需要一个自动发送邮件提醒的小功能,于是简单的研究了一下java的JMail来实现自动发送邮件的功能.已被后期需要参考. 一.准备 实现的原理很简单:发送人 , 中转的邮 ...
- BZOJ5418 NOI2018屠龙勇士(excrt)
显然multiset求出每次用哪把剑.注意到除了p=1的情况,其他数据都保证了ai<pi,于是先特判一下p=1.比较坑的是还可能存在ai=pi,稍微考虑一下. 剩下的部分即解bix≡ai(mod ...
- NOIP2017列队(phalanx)解题报告
列队作为NOIP2017最后一道题,其实并不难,只是相对于其它题目,有点小小的工业 首先,这道题我用splay维护的,如果你不会splay,又想学一下splay,可以来这里学一学,接下来步入正题 首先 ...
- 【BZOJ1965】[AHOI2005]洗牌(数论)
[BZOJ1965][AHOI2005]洗牌(数论) 题面 BZOJ 洛谷 题解 考虑反过来做这个洗牌的操作,假定当前牌是第\(l\)张. 因为之前洗的时候考虑了前一半和后一半,所以根据\(l\)的奇 ...
- Mountainous landscape
Description 现在在平面上给你一条折线 \(P_1P_2 \cdots P_n\) . \(x\) 坐标是严格单调递增的.对于每一段折线 \(P_iP_{i+1}\) ,请你找一个最小的 \ ...
- 【poj3693】 Maximum repetition substring
http://poj.org/problem?id=3693 (题目链接) 题意 给定一个字符串,求重复次数最多的连续重复子串,若存在多组解,输出字典序最小的. Solution 后缀数组论文题,就是 ...
- 解题:CF960G Bandit Blues & FJOI 2016 建筑师
题面1 题面2 两个题推导是一样的,具体实现不一样,所以写一起了,以FJOI 2016 建筑师 的题面为标准 前后在组合意义下一样,现在只考虑前面,可以发现看到的这a个建筑将这一段划分成了a-1个区间 ...