前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >final域是引用类型该如何写

final域是引用类型该如何写

原创
作者头像
好派笔记
修改2021-10-08 14:51:59
1850
修改2021-10-08 14:51:59
举报
文章被收录于专栏:好派笔记
代码语言:javascript
复制
public class FinalReferenceExample {
	final int[] intArray; // final是引用类型
	static FinalReferenceExample obj;

	public FinalReferenceExample() { // 构造函数
		intArray = new int[1]; // 1
		intArray[0] = 1; // 2
	}

	public static void writerOne() { // 写线程A执行
		obj = new FinalReferenceExample(); // 3
	}

	public static void writerTwo() { // 写线程B执行
		obj.intArray[0] = 2; // 4
	}

	public static void reader() { // 读线程C执行
		if (obj != null) { // 5
			int temp1 = obj.intArray[0]; // 6
		}
	}
}

  这里final域为一个引用类型,它引用一个int型的数组对象。对于引用类型,写final域的重排序规则对编译器和处理器增加了如下约束: 在构造函数内对一个final引用的对象的成员域的写入,与随后在构造函数外把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序。(即先对final域引用的对象赋值后才能读取此final域引用的对象)   对上面的示例程序,我们假设首先线程A执行writerOne()方法,执行完后线程B执行writerTwo()方法,执行完后线程C执行reader ()方法。下面是一种可能的线程执行时序:

  在上图中,1是对final域的写入,2是对这个final域引用的对象的成员域的写入,3是把被构造的对象的引用赋值给某个引用变量。这里除了前面提到的1不能和3重排序外,2和3也不能重排序。JMM(Java内存模型)可以确保读线程C至少能看到写线程A在构造函数中对final引用对象的成员域的写入。即C至少能看到数组下标0的值为1。而写线程B对数组元素的写入,读线程C可能看的到,也可能看不到。JMM不保证线程B的写入对读线程C可见,因为写线程B和读线程C之间存在数据竞争,此时的执行结果不可预知。   如果想要确保读线程C看到写线程B对数组元素的写入,写线程B和读线程C之间需要使用同步原语(lock或volatile)来确保内存可见性。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档