Singleton_模式_关于单例(Singleton)模式实现方式的反思

简介摘要: 大家都知道单例模式,也知道实现的方法,最近看到几个网友推荐的文章,仔细思考了一下,发现我以前的想法是有问题的。 先看我一直使用的单例代码样例: /** * 一段我一直使用的单例实现的代码。 大家都知道单例模式[mo shi],也知道实现的方法[fang fa],最近看到几个网友推荐的文章,仔细思考了一下,发现我以前的想法是有问题[wen ti]的。 先看我一直使用的单例代码[dai ma]样例: /** * 一段我一直使用的单例实现的代码[dai ma]。 * * @author 赵学庆,java世纪网(java2000.net) * */ public class Singleton { private static volatile Singleton instance; private Singleton() { } public static Singleton getInstance() { if (instance == null ) { // 1 synchronized (Singleton. class ) { // 2 if (instance == null ) // 3 instance = new Singleton(); // 4 } } return instance; } } 系统[xi tong]先判断是否已经初始化[chu shi hua](1), 如果没有初始化[chu shi hua]则进入同步[tong bu](2), 然后再次判断是否已经初始化[chu shi hua](3), 如果还是没有则初始化[chu shi hua]一个(4). 系统[xi tong]考虑了多CPU问题[wen ti],使用了 volatile 这个修饰符[xiu shi fu]。 我自认这个代码[dai ma]没有任何问题[wen ti],但是:?? 一个文章里说到的奇怪的执行[zhi hang]顺序引起了我的注意,我来说明[shuo ming]一下2个线程[xian cheng]的执行[zhi hang]过程: 线程[xian cheng]1这行到了(4),此时系统[xi tong]需要做的事情是给Singleton分配[fen pei]内容,然后进行初始化[chu shi hua],可是对instance的赋值[fu zhi]操作是在类初始化[chu shi hua]之前完成的。那没就会出现 线程[xian cheng]2 此时拿到了CPU,此时判断instance 已经不再是null,于是他使用了这个已经分配[fen pei]了内存[nei cun],但没有初始化[chu shi hua]完毕的类,然后造成运行[yun hang]结果异常[yi chang]。 这个问题[wen ti]我想还是很有可能的,毕竟我们无法保证JVM一定在类已经完全初始化[chu shi hua]完毕之后再赋值[fu zhi]给instance。因为这样做,系统[xi tong]要额外分配[fen pei]一个变量[bian liang]用来临时指向[zhi xiang]新分配[fen pei]的内存[nei cun],完成所有的初始化[chu shi hua]之后再把内存[nei cun]指向[zhi xiang]instance。而正常的理解,肯定是不会额外的浪费这个变量[bian liang]的(希望[xi wang]我的猜测是错的,我宁可我是错的)。 下面是我再次搜索[sou suo]并整理的更安全的初始化[chu shi hua]方法[fang fa],大家参考[can kao]看看: 第一种,使用静态初始化[chu shi hua] class Singleton { private static volatile Singleton instance = new Singleton(); private Singleton() { } public static Singleton getInstance() { return instance; } } 第二种,使用 静态 内部类[nei bu lei]进行初始化[chu shi hua] class Singleton { static class SingletonHolder { static volatile Singleton instance = new Singleton(); } private Singleton() { } public static Singleton getInstance() { return SingletonHolder.instance; } } 有评价[ping jia]说,第二种更加的安全。我能力[neng li]有限,实在不能窥透他们的区别,我只能按照保守的估算,在我以后的代码[dai ma]里,全部用第二种方法[fang fa]。 另外, 楼下网友提供的用临时变量[bian liang]的方法[fang fa],你可以参考[can kao]我的参考[can kao]文章,里面讲述了理由。在一些编译[bian yi]器[bian yi qi]优化[you hua]时,会把它优化[you hua]掉,造成并不能达到我们要的结果。也就是编译[bian yi]器[bian yi qi]会认为你的那个临时变量[bian liang]是多余的。 期待牛人能给个更准确的说法。 参考[can kao]文章: 1 解析 Java 类和对象[dui xiang]的初始化[chu shi hua]过程 2 Java中的模式[mo shi] --单态 3 The "Double-Checked Locking is Broken" Declaration

你可能感兴趣的:(java,jvm,优化,null,Class,locking)