public class Singleton{
private static volatile Singleton singleton;
private Singleton(){}
public Singleton getInstance(){
if(singleton==null){
synchronized(Singleton.class){
if(singleton==null){
singleton = new Singleton();
}
}
}
return singleton;
}
}
第一次加锁是为了减少synchronized的开销,如果第一次检测的singleton不为null,则不需要进行加锁初始化操作,因此可以大幅度降低synchronized带来的性能开销。
第二次检测是为了延迟初始化,只有当使用到该对象的时候才进行初始化。
为什么要volatile呢?
synchronized虽然保证了原子性,但是却没有保证重排序的正确性,会出现A线程执行的过程中,先把引用地址发布,但是还未进行构造函数的情况,这是如果B线程来访问,他会看见已经赋值好的实例地址,但是内容却是空的。
而volatile可以保证线程的可见性,并且可以禁止指令重排序。就会解决这种情况。
- 保证可见性,使用volatile定义的变量,将会保证对所有线程的可见性。
- 禁止指令重排序优化,由于volatile禁止创建指令之间的重排序,所以其他线程不会访问正在初始化的对象,从而保证线程的安全性。