单例和公共静态变量Java

时间:2012-12-05 13:21:46

标签: java singleton static-variables

我有两个选择:

  1. 单身人士模式

    class Singleton{
        private static Singleton singleton = null;
    
        public static synchronized Singleton getInstance(){
            if(singleton  == null){
                singleton = new Singleton();
            }
            return singleton;
        }
    }
    
  2. 使用static final字段

    private static final Singleton singleton = new Singleton();
    
    public static Singleton getSingleton() {
        return singleton;
    }
    
  3. 区别是什么? (单线程或多线程)

    更新:我知道Bill Pugh或enum方法。 我不是在寻找正确的方法,但我只使用过1.在1或2中是否有任何差异?

5 个答案:

答案 0 :(得分:10)

主要区别在于,使用第一个选项时,单例只会在调用getInstance时初始化,而使用第二个选项时,只要加载包含类,它就会被初始化。

懒惰且线程安全的第三个(首选)选项是使用枚举:

public enum Singleton {
    INSTANCE;
}

答案 1 :(得分:2)

有一点不同:

解决方案1是一个延迟初始化,将在第一次调用getInstance时创建单例实例

解决方案2是一个急切的初始化,单个实例将在类loades

时创建

它们都是线程安全的,调用第二个多线程是一个有点误导性的

答案 2 :(得分:2)

第一种解决方案似乎更懒惰,但实际上并非如此。

第一次访问静态方法/字段时会初始化类。

getInstance()可能是该类唯一可公开访问的静态方法/字段。这就是单身人士的观点。

然后,当有人第一次呼叫getInstance()时,该类会被初始化。这意味着两种解决方案在懒惰方面基本相同。

当然,第二种解决方案看起来更好,性能更好。

答案 3 :(得分:1)

因此,通过更新,上述两个选项都是线程安全的。但是synchronized选项要求每个调用instance的线程获取此锁,从而降低性能(如果这样做很多)。此外,在方法级别使用synchronized可能存在使用公共可用锁(类本身)的问题,因此如果某个线程获得此锁(可能),则可能最终导致死锁。 static final选项性能更高,但不会对单例进行延迟初始化(根据系统的不同,这可能不是问题)。

允许Singleton的线程安全延迟初始化的另一个选项如下:

 public class MySingleton{
      private static class Builder{
          private static final MySingleton instance = new MySingleton();
      }

      public static MySingleton instance(){
           return Builder.intance;
      }
 }

这是有效的,因为静态内部类被保证在执行包含类中的任何方法之前被初始化。

答案 4 :(得分:-1)

Java中的Singleton实现(如果你真的想要的话)可以比你描述的eager和lazy初始化更优雅的方式执行。检查Joshua Bloch描述的the enum way和Bill Pugh提出的the SingletonHolder solution

维基百科文章也是理解模式的良好开端,并且可以回答您的问题。