1.发布与逃逸
1.1 发布对象
发布的意思是是一个对象能够被当前范围之外的代码所使用
1.2 不安全发布
1.3 对象溢出
一种错误的发布,当一个对象还没有构造完成时,就使它被其他线程所见
逃逸带来的问题
2. 安全发布对象的4种方法
2.1安全发布对象
在静态初始化函数中初始化一个对象引用
将对象的引用保存到volatile类型的域或者AtomicReference对象中(利用volatile happen-before规则)
将对象的引用保存到某个正确构造对象的final类型域中(初始化安全性)
将对象的引用保存到一个由锁保护的域中(读写都上锁)
第一种:静态初始化构造单利
public class StaticDemo {
private StaticDemo(){}
private static StaticDemo instance = new StaticDemo();
private static StaticDemo getInstance(){
return instance;//当静态构造方法初始化加载的时候
//一定是安全发布的,但是不保证后续操作这个instance的安全
}
}
第二种:final域
public class FinalDemo {
private final Map<String,String> states;
public FinalDemo(){
states = new HashMap<>();
states.put("yojofly","yojofly");
}
}
第三种:volatile
//第一种单利模式,此时当多线程访问时候,可能存在instance == null都判断成功,返回多个实例的情况
public class VolatileDemo {
public VolatileDemo(){}
private static VolatileDemo instance;
public static VolatileDemo getInstance(){
if (instance == null){
instance = new VolatileDemo();
return instance;
}
return instance;
}
}
//第二种单利模式,为了方式上述问题,我们可以给getInstance方法加锁,或者代码块加锁
public class VolatileDemo {
public VolatileDemo(){}
private static VolatileDemo instance;
public static VolatileDemo getInstance(){
if (instance == null){
synchronized (VolatileDemo.class){
if (instance == null){
instance = new VolatileDemo();
return instance;
}
}
}
return instance;
}
}
上述代码加if (instance == null)的原因是,在第一次获取到为null的基础上,再做一次加锁,做判断,消除掉多线程获取if (instance == null)产生的结果相同的问题,但是在java层面
instance = new VolatileDemo();
是一句话,但是在jvm层面,这句话会被编译成多个指令
例如:指令 m,n,p,那么m,n,p指令的执行顺序一定是顺序执行的吗,此时依然存在指令重排序问题
第三种方法:volatile关键字
public class VolatileDemo {
public VolatileDemo(){}
private volatile static VolatileDemo instance; //给发布对象加上volatile关键字,防止指令重排序
public static VolatileDemo getInstance(){
if (instance == null){
synchronized (VolatileDemo.class){
if (instance == null){
instance = new VolatileDemo();
return instance;
}
}
}
return instance;
}
}