java语言规范规定JVM线程内部维持顺序化语义。即只要程序的最终结果与它顺序化情况的结果相等,那么指令的执行顺序可以与代码顺序不一致,此过程叫指令的重排序。
指令重排在单线程环境下不会出现问题,但是在多线程环境下会导致一个线程获得还没有初始化的实例。
如何解决指令重排问题:
volatile: 建立上下指令之间的内存屏障
好处: 解决指令之间的顺序问题,禁止重排序;
缺点: cpu利用率降低,因为顺序执行的原因,如果是一个thread存在多条指令,将会在一些较为耗时的
指令上花费较长时间,才能获取最终执行结果;
使用 DCL(double check lock) 双重锁机制
第一步提高效率先判断对象是否为空(不直接使用synchronized),如果已经存在,就直接返回对象即可;
第二步使用synchronized锁,保证多请求情况下指令的执行顺序;
第三步再次判断是否为空,如果为空:创建对象,绑定关系,返回对象;
代码如下,双重校验锁实现单例
//双重校验锁实现单例
public class synchronizedDemo {
//volatile 禁止jvm重排 保证内存的可见性
private volatile static synchronizedDemo uniqueIntance;
//private 构造函数私有化
private synchronizedDemo(){
}
private static synchronizedDemo getUniqueIntance(){
//锁外判断,避免每次进来都获取锁
if(null == uniqueIntance) {
synchronized (synchronizedDemo.class) {//锁内判断,避免多线程产生重复对象
if (null == uniqueIntance) {
uniqueIntance = new synchronizedDemo();
}
}
}
return uniqueIntance;
}
}