单例模式,不多说了,这个模式和静态函数有什么区别,之前解释过了,不是今天重点。
这个贴的重点是,单例模式的这个单例,如何初始化。
其实单例的初始化有两种:一种是提前初始化,就是说,在程序使用单例时,先由其他程序保证这个实例已经初始化结束。
这个比较简单,也不是本贴的重点。
另外一种就是程序一开始不初始化,仅仅在单例第一次被调用的时候被初始化。
中间怎么演变就不说了。总之这里技巧是要解决一个矛盾:第一次使用时初始化,就必需要用同步机制,在对象使用前是否已经初始化。
但是加锁后,极大的降低了程序的性能,尤其判断比较复杂的时候。曾经有文章在设计模式界批判“单例是魔鬼”就出于此。
现在很多的补充做法可以尽量的避免这种方式。文字不好解释,给个代码模型吧。
public class Singl{
   /**
   *单例形成,不允许外部实例化
   */
   private Singl(){
   }
   
   private static Singl instance;
   
   private Object lock = new Object();
   private static Singl getSingl(){
    if (instance == null){//第一次判断不要同步
    synchronized(lock){//第二次在上锁同步,且要再判断一次
    if (instance == null){//第一次判断不要同步
    instance = new Singl()
    }
    }
    }
    return instance;
   }
}
搞定!
还有其他的一些小技巧共享都放到我的空间中了,有兴趣的可以过来看看

解决方案 »

  1.   

    双重检查锁在 JDK 5 及以后的版本中如果单例成员没有加 volatile 关键字的话,
    在多线程环境中可能会产生不止一个的实例。双重检查锁在 JDK 5 以下的版本完全无效。建议采用强制初始化单例成员。在很多资源上都有说明为什么双检锁在 Java 中是无效的:Effective Java
    The "Double-Checked Locking is Broken" Declaration
    双重检查锁定及单例模式
      

  2.   

    受教了,我查了一篇写的比较详细的文章:
    public static Singleton getInstance()
    {
      if (instance == null)
      {
        synchronized(Singleton.class) {  //1
          if (instance == null)          //2
            instance = new Singleton();  //3
        }
      }
      return instance;
    }
    其中,instance = new Singleton();  的指令码伪码为:
    mem = allocate();             //Allocate memory for Singleton object.
    instance = mem;               //Note that instance is now non-null, but
                                  //has not been initialized.
    ctorSingleton(instance);      //Invoke constructor for Singleton passing
                                  //instance.换句话说,如果当同步块中执行到伪码:
    mem = allocate();
    instance = mem;
    时(这时对象已经创建,但没初始化),正好另外一个线程进入并执行到为同步的判断块
    if (instance == null)时,就会直接返回一个未初始化的对象了。
      

  3.   

    在资料上说:
    package single;/**
     *
     * @author l33187
     */
    public class Single {
        public static Single s = null;
        public static Object lock = new Object();
        private int a = 0;
        
        private Single(){
            this.a = 100;
        }
        public Single getSingle(){
            if (s == null){
                synchronized(lock){
                    if (s == null){
                        Single tmp = new Single();                    
                        s = tmp;
                    }
                }
            }
            return s;
        }
    }
    理论上是可以解决问题的,但是在java编译时做的优化。
    会将临时变量给优化掉。
    但是,我拿反编译工具,查看反编译后的结果,并没有看到优化掉啊?这个优化后的结构怎么看呢?有没有高手知道?