wordpress加dz重庆seo整站优化方案范文
volatile原理
volatile的底层实现原理是内存屏障,Memory Barrier(Memory Fence)
· 对volatile变量的写指令后会加入写屏障
· 对volatile变量的读指令前会加入读屏障
如何保证可见性
写屏障保证在该屏障之前的,对共享变量的改动,都同步到主存当中
public void actor2(I_Result r){num = 2;ready = true;// ready 是volatile 赋值带写屏障//写屏障
}
而读屏障保证在该屏障之后,对共享变量的读取,加载的是主存中最新数据
public void actor1(I_Result r){//读屏障//ready 是 volatile 读取值带读屏障if(ready){r.r1 = num + num;}else{r.r1 = 1;}
}
如何保证有序性
写屏障会确保指令重排序时,不会将写屏障之前的代码排在写屏障之后
public void actor2(I_Result r){num = 2;ready = true;// ready 是volatile 赋值带写屏障//写屏障
}
读屏障会确保指令重排序时,不会将读屏障之后的代码排在读屏障之前
public void actor1(I_Result r){//读屏障//ready 是 volatile 读取值带读屏障if(ready){r.r1 = num + num;}else{r.r1 = 1;}
}
写屏障仅仅是保证之后的读能够读到最新结果,但不能保证读跑到它前面去
而有序性的保证也只能保证了本线程内相关代码不被重排序
double-checked locking 问题
以著名的double-checked locking 单例模式为例
public final class Singleton{private Singleton(){}private static Singleton INSTANCE = null;public static Singleton getInstance(){// 首次访问会同步,而之后的使用没有synchronizedif(INSTANCE == null){synchronized(Singleton.class){if(INSTANCE == null){INSTANCE = new Singleton();}}} return INSTANCE;}
}
以上的实现特点是:
懒惰实例化
首次使用getInstance()才会调用synchronized加锁,后续使用时无需加锁
有隐含的,但很关键的一点:第一个if使用了INSTANCE变量,是在同步块之外
但是在多线程环境下,上面的代码是有问题的,getInstance方法对应的字节码为:
其中
· 17 表示创建对象,将对象引用入栈 //new Singleton
· 20 表示复制一份对象引用 //引用地址
· 21 表示利用一个对象引用,调用构造方法 //引用地址调用
· 24 表示利用一个对象引用,赋值给static INSTANCE
也许jvm会优化为: 先执行24,再执行21。如果这两个线程t1,t2按如下时间序列执行:
synchronized只能保证代码块内部的原子性,可见性,有序性,但是INSTANCE并不是都在synchronized内部所以出现了指令重排的问题
double-checked locking 解决
public final class Singleton{private Singleton(){}private static volatile Singleton INSTANCE = null;public static Singleton getInstance(){// 首次访问会同步,而之后的使用没有synchronizedif(INSTANCE == null){synchronized(Singleton.class){if(INSTANCE == null){INSTANCE = new Singleton();}}} return INSTANCE;}
}