单例类有很多种,有饿汉式,懒汉式。其中懒汉式由于其两次判断被称为双重检测单例类。
看一段代码。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 public class StoreKeeper { 2 /** 属性列表值. */ 3 private HashMap<String, Store> storepool = null; 4 private HashMap<String, Long> lifepool = null; 5 private static StoreKeeper instance; 6 private StoreKeeper(){ 7 storepool = new HashMap<String, Store>(); 8 lifepool = new HashMap<String, Long>(); 9 } 10 public static StoreKeeper getInstance(){ 11 if (instance == null) { 12 synchronized (StoreKeeper.class) { 13 if (instance == null) { 14 instance = new StoreKeeper(); 15 } 16 } 17 } 18 return instance; 19 }
双重检测单例类即不会每次调用都要获取锁,又做到了延迟加载所以大家都喜欢使用到这种方式,但是双重检测模式在java里面有些问题,主要是JVM会对代码执行重排序等其他的优化策略,所以导致可能返回的实例对象中的成员变量还没有初始化,导致其他线程引用这个对象时得到的成员变量数据不一致,因为获取到的这个实例中的成员变量还未初始化为用户指定的值
解决方法:
在实例变量增加关键字volatile
private static volatile StoreKeeper instance;
这样就不会出现问题了,因为jvm看到有这个volatile关键字就不会对这段代码
进行重排序优化,所以双重检测机制都要求加上这个volatile关键字.