双重校验锁
上图单线程安全。
先判断null如果为null再尝试获取锁(提高性能,如果已经创建就不用加锁判断了),获取锁后还不能直接创建,因为之前可能也有判断为null的已经获取过锁并创建对象,所以锁内需要再次检测。两次的if判断与synchronized称为双重校验锁。
为什么要加volatile
因为在上述if判断即使加锁了还是可能出错。
new可分为几步
1、检查类是否加载
2、分配内存
3、变量赋默认值
4、设置对象头
5、执行初始化方法
简单说,先分配内存,再执行构造器方法,最后引用赋值给变量。
由于指令会重排序后两步可能颠倒导致多线程下在对象进行分配内存、变量赋值还未初始化时就被使用。
volatile两个作用
1、多线程下保证可见性
2、禁止指令重排序
volatile 禁止对象创建时指令之间重排序,所以其他线程不会访问到一个未初始化的对象,从而保证安全性