第一种形式是
public class Singleton { 
  private Singleton(){} 
  
  private static final Singleton instance = new Singleton(); 
  
  public static Singleton getInstance() { 
    return instance;
  } 

第二种形式是: 
public class Singleton { 
  private Singleton(){}   private static Singleton instance = null;  public static synchronized Singleton getInstance() { 
    if (instance==null){ 
      instance=new Singleton(); 
    }
    return instance;
  } 

这是网上两种常见的singleton写法。但我觉得第二种写法应该是错误的,因为instance变量没有final修饰,所以有可能被方法改变,实例有可能不是single的了,这有点违背singleton的精神,你以为呢

解决方案 »

  1.   

    不可能被改变啊,没有改变他的方法 第一次调用getInstance是生成实例 而且 是synchronized
      

  2.   

    假如这样呢:
    public class Singleton { 
      private Singleton(){}   private static Singleton instance = null;  public static synchronized Singleton getInstance() { 
        if (instance==null){ 
          instance=new Singleton(); 
        }
        return instance;
      }
      
      public static void anyMethod(){
        instance=new Singleton();
        instance=new Singleton();
        instance=new Singleton();
        instance=new Singleton();
      }

    可能你会保证,我怎么会写出这么愚蠢的代码,但你能说没有这种可能性么?
      

  3.   

    第一个NEW生成实例,后面的NEW就是直接返回引用了!
      

  4.   

    scjpsz1860() ( )呵呵,别搞笑好不好
      

  5.   

    Sorry,发贴发错了,private隐含着final是针对方法的:)
    楼主的问题不是问题了,单例类的两种方式,前者是饿汉式,后者是懒汉式。后者因为在使用时才创建实例,能够节约一些系统资源。不过好像节约的效果不明显
      

  6.   

    public static void anyMethod(){
        instance=new Singleton();
        instance=new Singleton();
        instance=new Singleton();
        instance=new Singleton();
      }
    =============================
    单例模式是不允许你怎么做的,因为他会把构造函数私有化,使得你不可能在分配一个新的实例.就是说楼主你的代码里面少了这句:
    private 构造名(){}
      

  7.   

    楼主钻牛角尖了,而且楼主对设计模式的概念还没有理解透.设计模式不是算法,没有什么"固定"的写法,这两种例子都是对singleton的举例说明,并没有说一定要这样写才叫singleton
    实际上singleton设计模式的主要目的是不让类的外部调用者随意实例该singleton,并不是说只有一个实例才叫singleton,在实际写代码时我们也会在一个singleton中产生多个实例以供使用,这样做并没有什么问题,也没有违背singleton的理念.比如
    public class Singleton { 
      private Singleton(){}   private static Singleton instance1 = null;
        private static Singleton instance2 = null;
      public static synchronized Singleton getInstanceOne() { 
        if (instance1==null){ 
          instance1=new Singleton(); 
        }
        return instance1;
      }
      
        public static synchronized Singleton getInstanceTwo() { 
        if (instance2==null){ 
          instance2=new Singleton(); 
        }
        return instance2;
      }
    }
      

  8.   

    至于楼主的
    public static void anyMethod(){
        instance=new Singleton();
        instance=new Singleton();
        instance=new Singleton();
        instance=new Singleton();
      }
    =============================
    在实际情况下始终只有一个实例会被外部类调用,其他的实例会在失去引用一段时间以后被垃圾回收
      

  9.   

    public static void anyMethod(){
        instance=new Singleton();
        instance=new Singleton();
        instance=new Singleton();
        instance=new Singleton();
      }
    我当然知道这儿最后只会剩一个实例,这只是我举的个极端的例子,我觉得钻牛角尖的好像不是我,我再举个像是实际应用的例子吧public class Test{
        public static void main(String[] args){
            Singleton obj = null;
            obj = Singleton.getInstance();
            obj.someOperation();        obj = Singleton.getInstance();
            obj.printStatus();
            //我们有可能期望输出是"status is operated!",实际却是"status is initialized!"
        }
    }class Singleton {  private static Singleton instance = null;
      private String status = null;

      private Singleton(){
        status = "status is initialized!";
      }   public static synchronized Singleton getInstance() { 
        if (instance==null){ 
          instance=new Singleton(); 
        }
        return instance;
      }
      
      public void someMethod(){
        instance = null;
        //一些其它代码...
      }    public void someOperation(){
        status = "status is operated!";
        someMethod();
      }  private void printStatus(){
        System.out.println(status);
      }
    } 注:
    在此我不想跟大家争论我们会不会在实际应用中写出这样的代码,或者真有这样的特殊要求,我想跟大家探讨的是第二种模式代码无法阻止我们写违背singleton精神的代码。
      

  10.   

    如果你不想遵守singleton的精神 怎么都有办法破环。你用不同的ClassLoader就可以不断的生成任何一个类的实例。因为java的 static 并不能保证绝对唯一。而是保证在一个ClassLoader中唯一。赫赫
      

  11.   

    请问搂住:单例模式为什么要private 构造方法?
    再问搂住:你为什么要在单件类里调用它的构造方法?因为你想证明单件模式不适真正的单件模式?人家设计这个模式就是为了让你在外部得到一个且只有一个对象(在同一个JVM里)。
    最后问搂住:public void someMethod(){
             instance = null;    //这句干哈用?我认为上面那个类的结果
             //一些其它代码...
              }
    最最后问搂住:obj.printStatus(); 能调用吗?
      

  12.   

    private static Singleton instance = null;  public static synchronized Singleton getInstance() { 
        if (instance==null){ 
    //如果instance 是final的,那么下面这一行肯定是错误的,因为final修饰的变量的值不能
    被修改!
          instance=new Singleton(); 
        }
        return instance;
      } 
      

  13.   

    public void someMethod(){
        instance = null;
        //一些其它代码...
      }
    -------------------
    楼主真是钻牛教间了,随便在内部将实例变量赋值为空,如果想用单态模式的话最好不要这样,除非您想来抬杠。
      

  14.   

    已经说过了, 根本用不着第二种, 第一种天生就是 lazy init + thread safe , 第二种纯属画蛇添足.java:
    一个类 class ,第一次被调用时, 才会载入内存.java 又不是 c/c++ , static 变量在 c/c++ 中是载入程序时初始化的.
      

  15.   


    第二种适合C++, 对Java就没有多少意义了. 
      

  16.   

    我喜欢第一种;但是依然解决不了多线程创建对象的问题;最好同步当前类
    public class Singleton { 
      private Singleton(){}   private static Singleton instance = null;  public static Singleton getInstance() {
            synchronized (Singleton.class){
        if (instance==null){ 
          instance=new Singleton(); 
        }
         }
        return instance;
      } 

      

  17.   

    op1:如果楼主认为第二种是错误的,那么第一种方法同样也可以通过类或者对象的方法来改变其引用的对象.这些东西都是靠自己去做的,如果你认为的去改变,也就不存在什么设计了.op2:第一种方法根本不需要去为当前类加线程锁,去看看虚拟机是如何初始化一个类的,当解析静态变量的时候,自动就是同步的,不会存在多线程的问题.
      

  18.   

    重复一遍:
    第一种天生就是 lazy init + thread safe既不需要 lazy init 也不需要 同步, 不管是 实例 还是 类.lazy init + thread safe 完全是由 jvm 的机制自动解决的.
      

  19.   

    构造函数已经private了,还怎么new??????
      

  20.   

    1. singleton 模式的 构造函数 必须是 private ,只可能类内部调用, 保证从外部不能调用, 确保实例的单一性.2. 第一种, 在仔细编码的情况下, 可以保证 线程安全.2. 第二种, 无需任何同步代码, jvm 决定了 线程安全.
      

  21.   

    楼主,你的想法虽然奇怪了点,不过我还是能理解的,的确你那样的例子会出现你所想的问题,但前提是以上所有的都是开发人员应该尽量避免的,正如模式2,既然这样写了,那写这个class出来的人,他肯定就不应该instance=null出现这样的情况,如果要出现,那他应该重新设计,那些signleton模式都是一种写法,你要去遵守这个规则,如果你非要打破这个规则,那就只能自己去设计适合自己的模式了,正如signleton模式,就是避免别的人再去new ,但如果你本身要去改变signleton类自己的话,那这个。。其实也就不是signleton模式,是你自己的模式,总结:signleton模式是人家的,我们是要遵守规则的,如果你要改变的,请你自己注意的
      

  22.   

    LZ有上面的想法和我以前遇到的情况相似,就是单例模式中的单例需要实现很多静态的接口,这些接口能够调用构造函数,所以可能出现错误调用的情况,内部创建多个实例,导致资源和性能的浪费。我的解决方案有两个:
    1,除了GetInstance外,所有的函数都不能调用自己的构造函数,也不能对实例进行修改,只能调用GetInstance来取得自己的实例,然后调用这个实例的方法,容易目测。不能肯定保证。
    2,在单例模式类之外再包裹一层类。里面的类只负责GetInstance函数的实现。外面的类负责别的静态函数的实现,这样问题就没有了。
    以上。
      

  23.   

    LZ的想法可能有点问题。
    在这个类Singleton 的外部,不可能再得到第二个实例化的对象了,这应该是Singleton 模式想说明的意思。
      

  24.   

    第二种根本就不是singlton模式,楼主不要混淆了,
    monostate看看~
      

  25.   

    Russellzheng(一条裤子) ( ) 信誉:100  2006-3-24 9:05:56  得分: 0  
       
    楼主钻牛角尖了,而且楼主对设计模式的概念还没有理解透.设计模式不是算法,没有什么"固定"的写法,这两种例子都是对singleton的举例说明,并没有说一定要这样写才叫singleton
    实际上singleton设计模式的主要目的是不让类的外部调用者随意实例该singleton,并不是说只有一个实例才叫singleton,在实际写代码时我们也会在一个singleton中产生多个实例以供使用,这样做并没有什么问题,也没有违背singleton的理念.比如
    public class Singleton { 
      private Singleton(){}   private static Singleton instance1 = null;
        private static Singleton instance2 = null;
      public static synchronized Singleton getInstanceOne() { 
        if (instance1==null){ 
          instance1=new Singleton(); 
        }
        return instance1;
      }
      
        public static synchronized Singleton getInstanceTwo() { 
        if (instance2==null){ 
          instance2=new Singleton(); 
        }
        return instance2;
      }
    }
    ==============================================
    这种情况就不能用第一种写法了么?
    public class Singleton { 
      private Singleton(){}   private static final Singleton instance1 = new Singleton();
        private static final Singleton instance2 = new Singleton();
      public static Singleton getInstanceOne() { 
        return instance1;
      }
      
        public static Singleton getInstanceTwo() { 
        return instance2;
      }
    }
      
    tomtailer() ( ) 信誉:100  2006-3-24 17:33:20  得分: 0  
       
    public void someMethod(){
        instance = null;
        //一些其它代码...
      }
    -------------------
    楼主真是钻牛教间了,随便在内部将实例变量赋值为空,如果想用单态模式的话最好不要这样,除非您想来抬杠。
    =================================
    我说过我不探讨实际会不写出这样的代码了
    假如程序中用到一个相似拼写的变量如instace在附近,你无意中拼成了instance,第一种写法不会编译通过,第二种就有可能出现问题了,我在探讨的是代码的健壮性
     
    Top  
     crazycy(崔毅) ( ) 信誉:101  2006-3-24 22:49:00  得分: 0  
       
    我喜欢第一种;但是依然解决不了多线程创建对象的问题;最好同步当前类
    public class Singleton { 
      private Singleton(){}   private static Singleton instance = null;  public static Singleton getInstance() {
            synchronized (Singleton.class){
        if (instance==null){ 
          instance=new Singleton(); 
        }
         }
        return instance;
      } 

    ===================================================
    第一种线程不同步么?这个我确实不清楚,不过我想第一种方法是在类实例化的时候给变量赋值,不会出现不同步的情况吧,要不然类里的变量还有可能只初始化了一半?这好像不太可能吧?
     
    Top  
     foxty(狐狸糊涂) ( ) 信誉:100  2006-3-24 23:21:31  得分: 0  
       
    op1:如果楼主认为第二种是错误的,那么第一种方法同样也可以通过类或者对象的方法来改变其引用的对象.这些东西都是靠自己去做的,如果你认为的去改变,也就不存在什么设计了.op2:第一种方法根本不需要去为当前类加线程锁,去看看虚拟机是如何初始化一个类的,当解析静态变量的时候,自动就是同步的,不会存在多线程的问题.
    ====================================================
    你好像连final关键字还不知道怎么用呢吧
      
     cool_ice(冷冰) ( ) 信誉:99  2006-3-25 3:39:45  得分: 0  
      
    构造函数已经private了,还怎么new??????
    =========================================
    你可能还不知道单例是怎么回事  
     
     
     fantasy1999(黄滕酒) ( ) 信誉:100  2006-3-25 12:12:18  得分: 0  
       
    呵呵~~~看来楼主才入门啊~~不过,语言不同~~要获得单例的方式,确实是有所不同啊~~
    最好是,楼主用所有自己了解的支持面向对象的语言统统实现一遍~~那样可能对此就理解更深了==========================================
    ?????
      
     
     supersunyi(赖赖虫) ( ) 信誉:97  2006-3-25 16:19:36  得分: 0     
    楼主,你的想法虽然奇怪了点,不过我还是能理解的,的确你那样的例子会出现你所想的问题,但前提是以上所有的都是开发人员应该尽量避免的,正如模式2,既然这样写了,那写这个class出来的人,他肯定就不应该instance=null出现这样的情况,如果要出现,那他应该重新设计,那些signleton模式都是一种写法,你要去遵守这个规则,如果你非要打破这个规则,那就只能自己去设计适合自己的模式了,正如signleton模式,就是避免别的人再去new ,但如果你本身要去改变signleton类自己的话,那这个。。其实也就不是signleton模式,是你自己的模式,总结:signleton模式是人家的,我们是要遵守规则的,如果你要改变的,请你自己注意的
    =============================
    见上面回复tomtailer()
      
     
     flyfreely(林雨亭) ( ) 信誉:100  2006-3-25 19:11:54  得分: 0  
       
    LZ有上面的想法和我以前遇到的情况相似,就是单例模式中的单例需要实现很多静态的接口,这些接口能够调用构造函数,所以可能出现错误调用的情况,内部创建多个实例,导致资源和性能的浪费。我的解决方案有两个:
    1,除了GetInstance外,所有的函数都不能调用自己的构造函数,也不能对实例进行修改,只能调用GetInstance来取得自己的实例,然后调用这个实例的方法,容易目测。不能肯定保证。
    2,在单例模式类之外再包裹一层类。里面的类只负责GetInstance函数的实现。外面的类负责别的静态函数的实现,这样问题就没有了。
    以上。
    =========================================
    我想用第一种方法能解决这个问题吧  
     
    Top  
     action_520_12(小马哥) ( ) 信誉:100  2006-3-25 23:22:49  得分: 0  
     
     
       
    LZ的想法可能有点问题。
    在这个类Singleton 的外部,不可能再得到第二个实例化的对象了,这应该是Singleton 模式想说明的意思。===============================================
    我想不只是这个意思,内部也不应该再有第二个实例化对象,singleton还应该还有点全局变量的意思。
      

  26.   

    effective java中好象有精辟的解释,在第一章就有的,singleton!
      

  27.   

    不觉得哦. 第二种方式由内部所控制,实现者可以保证它不会被修改.
    其实两种方式都不够好. 第一种方式的扩展是 static initialize block. 使用静态初始化块能对单件实例进行更多的操作与扩展.第二种方式的扩展是必须考虑到多线程的情况, 在创建之时要保证多线程安全.
      

  28.   

    realdreamer(楼主英明,贫僧久仰大名,特来拜见) ( ) 信誉:99  2006-03-27 11:05:00  得分: 0  
     
       不觉得哦. 第二种方式由内部所控制,实现者可以保证它不会被修改.
    其实两种方式都不够好. 第一种方式的扩展是 static initialize block. 使用静态初始化块能对单件实例进行更多的操作与扩展.第二种方式的扩展是必须考虑到多线程的情况, 在创建之时要保证多线程安全
    ================================================================怎么这么多人注意不到final呢?实在令人不解
     
      

  29.   

    dreamover(梦醒了) 不注意final是因为没有必要。
      

  30.   

    dreamover(梦醒了)  加上final也不现实。楼住的java语法还是要回去啃啃啊。“但我觉得第二种写法应该是错误的,因为instance变量没有final修饰,所以有可能被方法改变,实例有可能不是single的了,这有点违背singleton的精神,你以为呢”
    private final static Singleton instance = null;你已经final了它还能new它吗? 纵观你的此帖所有评论,语气还是比较嚣张第!态度不对!也许你现在还没有想清楚你哪里专牛角尖了,没关系,过一段时间就好了。
      

  31.   

    呵呵,系统启动module可以用第一种,也应该用第一种,反正要实例化,但不要所有都用第一种,如果你的application有100个singleton,其实初始化只需要10个核心module,都用第一种,你想想启动会有多么缓慢,第二种,往往lock和unlock不是一个big issue,所以,合理使用,每种都需要
      

  32.   

    lesstif(mobexpert) ( ) 信誉:100 呵呵,系统启动module可以用第一种,也应该用第一种,反正要实例化,但不要所有都用第一种,如果你的application有100个singleton,其实初始化只需要10个核心module,都用第一种,你想想启动会有多么缓慢,第二种,往往lock和unlock不是一个big issue,所以,合理使用,每种都需要
    ==========================================你这个理由不算理由,上面已经有人讲过了,java中static天生就是lazy init的了,这个你写个程序试一下就知道了,static变量也是在第一次调用时才被创建的
      

  33.   

    可以来分析一下楼主的例子,希望能够解决你的问题
    public class Test{
        public static void main(String[] args){
            Singleton obj = null;
            obj = Singleton.getInstance();
            obj.someOperation();        obj = Singleton.getInstance();
            obj.printStatus();
            //我们有可能期望输出是"status is operated!",实际却是"status is initialized!"
        }
    }class Singleton {  private static Singleton instance = null;
      private String status = null;  private Singleton(){
        status = "status is initialized!";
      }   public static synchronized Singleton getInstance() { 
        if (instance==null){ 
          instance=new Singleton(); 
                System.out.println("instance is null");//new add
        }
            /** new add begin */
            else
            {
                System.out.println("instance is null");
            }
            /** new add end*/
        return instance;
      }
      
      public void someMethod(){
        instance = null;
        //一些其它代码...
      }    public void someOperation(){
        status = "status is operated!";
        someMethod();
      }  private void printStatus(){
        System.out.println(status);
      }

    我们可以在if判断中加入else打印一下结果,执行上述语句的确是楼主所有的结果:
    instance is null
    status is operated!
    instance is null
    status is initialized!
    是因为楼主在getInstance以后又执行了someOperation()方法,someOperation()调用了someMethod()方法,而someMethod()方法中则将对象又指向了null,而下次getInstance()时候又会重新指向Singleton,在执行printStatus(),打印会是"status is initialized!"。如果你把someMethod()方法中的instance==null;注释掉,再执行一下,看看是不是楼主想要的结果。