深入理解 Java final 变量的内存模型
⊙对于 final 域,编译器和处理器要遵守两个重排序规则:
⊙在构造函数内对一个 final 域的写,与随后把这个构造对象的引用赋值给一个变量,这两个操作之间不能重排序
初次读一个包含 final 域的对象的引用,与随后初次读这个 final 域,这两个操作之间不能重排序
举个例子:
这里假设一个线程 A 执行 writer ()方法,随后另一个线程 B 执行 reader ()方法。
写 final 域的重排序规则
在写 final 域的时候有两个规则:
⊙JMM 禁止编译器把 final 域的写重排序到构造函数之外
⊙编译器会在 final 域的写之后,构造函数 return 之前,插入一个 StoreStore 屏障,这个屏障禁止处理器把 final 域的写重排序到构造函数之外。
分析上面的代码。
write 方法,只包含一行 obj = new FinalExample();,但是包含两个步骤:
⊙构造一个 FinalExample 对象
⊙把对象的引用赋值给 obj
假设线程 B 当中读 obj 与读成员域之间没有重排序。
写 final 域的重排序规则可以确保:在对象引用为任意线程可见之前,对象的 final 域已经被正确初始化过了,而普通域不具有这个保障。
读 final 域的重排序规则
读 final 域的重排序规则如下:
⊙在一个线程中,初次读对象引用与初次读该对象包含的 final 域,JMM 禁止处理器重排序这两个操作(注意,这个规则仅仅针对处理器)。编译器会在读 final 域操作的前面插入一个 LoadLoad 屏障。
reader() 方法包含三个操作:
1.初次读引用变量 obj;
2.初次读引用变量 obj 指向对象的普通域 j。
3.初次读引用变量 obj 指向对象的 final 域 i。
现在我们假设写线程 A 没有发生任何重排序,那么执行时序可能是:
可以看到对普通变量 i 的读取重排序到了读对象引用之前,在读普通域时候,该域还没被写线程 A 写入,这是一个错误的读取操作。而读 final 域已经被 A 线程初始化了,这个读取操作是正确的。
读 final 域的重排序规则可以确保:在读一个对象的 final 域之前,一定会先读包含 这个 final 域的对象的引用。在这个示例程序中,如果该引用不为 null,那么引用 对象的 final 域一定已经被 A 线程初始化过了。
如果 final 域是引用类型
如果 final 域是引用类型,写 final 域的重排序规则对编译器和处理器增加了如下约束:
⊙在构造函数内对一个 final 引用的对象的成员域的写入,与随后在构造函数外把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序。
如下代码例子:
假设首先线程 A 执行 writerOne()方法,执行完后线程 B 执行reader 方法,JMM 可以确保读线程 B 至少能看到写线程 A 在构造函数中对 final 引用对象的成员域的写入。
避免对象引用在构造函数当中溢出
代码如下:
假设一个线程 A 执行 writer()方法,另一个线程 B 执行 reader()方法。
这里的操作 2 使得对象还未完成构造前就为线程 B 可见。即使这里的操作 2 是构造函数的最后 一步,且即使在程序中操作 2 排在操作 1 后面,执行 read()方法的线程仍然可能无 法看到 final 域被初始化后的值,因为这里的操作 1 和操作 2 之间可能被重排序。
在构造函数返回前,被构造对象的引用不能为其他线程可 见,因为此时的 final 域可能还没有被初始化。在构造函数返回后,任意线程都将 保证能看到 final 域正确初始化之后的值。
感谢大家阅读java培训机构分享的“深入理解 Java final 变量的内存模型”本文由小编转载自网络,版权归原作者所有,旨在分享提供阅读,更多精彩内容请关注Java培训官网
【免责声明】本文部分系转载,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责,如涉及作品内容、版权和其它问题,请在30日内与我们联系,我们会予以重改或删除相关文章,以保证您的权益!
Java开发高端课程免费试学
大咖讲师+项目实战全面提升你的职场竞争力
- 海量实战教程
- 1V1答疑解惑
- 行业动态分析
- 大神学习路径图
相关推荐
更多2015-10-15
2015-10-15
达内就业喜报
更多>Java开班时间
-
北京 丨 11月27日
火速抢座 -
上海 丨 11月27日
火速抢座 -
广州 丨 11月27日
火速抢座 -
兰州 丨 11月27日
火速抢座 -
杭州 丨 11月27日
火速抢座 -
南京 丨 11月27日
火速抢座 -
沈阳 丨 11月27日
火速抢座 -
大连 丨 11月27日
火速抢座 -
长春 丨 11月27日
火速抢座 -
哈尔滨 丨 11月27日
火速抢座 -
济南 丨 11月27日
火速抢座 -
青岛 丨 11月27日
火速抢座 -
烟台 丨 11月27日
火速抢座 -
西安 丨 11月27日
火速抢座 -
天津 丨 11月27日
火速抢座 -
石家庄 丨 11月27日
火速抢座 -
保定 丨 11月27日
火速抢座 -
郑州 丨 11月27日
火速抢座 -
合肥 丨 11月27日
火速抢座 -
太原 丨 11月27日
火速抢座 -
苏州 丨 11月27日
火速抢座 -
武汉 丨 11月27日
火速抢座 -
成都 丨 11月27日
火速抢座 -
重庆 丨 11月27日
火速抢座 -
厦门 丨 11月27日
火速抢座 -
福州 丨 11月27日
火速抢座 -
珠海 丨 11月27日
火速抢座 -
南宁 丨 11月27日
火速抢座 -
东莞 丨 11月27日
火速抢座 -
贵阳 丨 11月27日
火速抢座 -
昆明 丨 11月27日
火速抢座 -
洛阳 丨 11月27日
火速抢座 -
临沂 丨 11月27日
火速抢座 -
潍坊 丨 11月27日
火速抢座 -
运城 丨 11月27日
火速抢座 -
呼和浩特丨11月27日
火速抢座 -
长沙 丨 11月27日
火速抢座 -
南昌 丨 11月27日
火速抢座 -
宁波 丨 11月27日
火速抢座 -
深圳 丨 11月27日
火速抢座 -
大庆 丨 11月27日
火速抢座