作者:今生绝恋2702934494 | 来源:互联网 | 2023-10-17 21:10
概述文本探讨构造函数是否为原子性问题。案例我们首先如下代码:publicclassPerson{publicintage;publicPerson(){age
概述
文本探讨构造函数是否为原子性问题。
案例
我们首先如下代码:
public class Person {public int age;public Person() {age=20;}
}
public class JavaMain {public static void main(String[] args) {Person person = new Person();}
}
请问Person person = new Person();
是否为原子性操作?
下图为main
函数的字节码:
我们可以看到构建一个类大致可以分为4
步骤:
new
指令申请堆栈空间,并且会生成一个引用放入函数的栈帧的栈顶。dup
复制栈顶,那么此处会在栈顶存在两个Person
堆内存地址引用.invokespecial
弹窗栈顶Person
并调用初始化函数- 将栈顶的剩余的
Person
引用弹窗复制到本地变量槽1中
可见一个构造一个对象并非原子性操作,那么这会带来哪些多线程问题?
public class JavaMain {static Person person;public static void main(String[] args) {new Thread("Thread One") {@Overridepublic void run() {super.run();person = new Person();}}.start();new Thread("Thread Two") {@Overridepublic void run() {super.run();if (person != null) {System.out.println(person.age);}}}.start();}
}
上面会发生 data race
(数据竞争)情况,上面的代码在极端情况可能会输出0
.
原因调用初始化函数
步骤 和将栈顶引用复制回Main
的person
发生了重排序。
解决方案一:
利用Pesron
的age
字段使用final
修饰.
public class Person {final public int age;public Person() {age = 20;}
}
关于final
语义后文讲解.
其他解决方案:
1.同步锁
2.volatile
修饰
3.利用happer-before
关系防止重排序(volatile原理)
4. 略