Java中的Singleton类是否可以接受?

时间:2015-07-04 20:12:12

标签: java design-patterns singleton

我使用了已发布的Singleton创建教程中的概念,但希望得到一些反馈。有没有首选方法?

public class MyDoubleLockSingleton {

    private volatile static Object _mySingleton;

//private constructor
    private MyDoubleLockSingleton() {
        if (_mySingleton == null) {
            MyDoubleLockSingleton.getSingleton();
        }
    }

//  double lock singleton approach
    public static Object getSingleton() {
        synchronized (MyDoubleLockSingleton.class) {
            if (_mySingleton == null) {
            _mySingleton = new Object();
        }
        return (Object)_mySingleton;
        }
    }
}

5 个答案:

答案 0 :(得分:1)

看起来更像是这样:

public class MyDoubleLockSingleton {

    private static final Object _lock = new Object(); // synchronize on this instead of MyDoubleLockSingleton.class
    private volatile static MyDoubleLockSingleton _mySingleton;

    //private constructor
    private MyDoubleLockSingleton() {
        // perform expensive initialization here.
    }

    //  double lock singleton approach
    public static MyDoubleLockSingleton getSingleton() {
        if (_mySingleton == null) {
            synchronized (_lock) {
                if (_mySingleton == null) {
                    _mySingleton = new Object();
                }
            }
        }
        return _mySingleton;
    }
}
  • 私有构造函数是您执行昂贵初始化的地方。
  • 最好在私人会员上同步。
  • 您可能希望在同步块中添加空检查 以提高性能。否则,这种模式没有多大意义。

现在,如果您的私有构造函数的代码并不昂贵,那么尝试执行延迟初始化确实没有任何意义。在这种情况下,请保持这样简单:

public class MyDoubleLockSingleton {

    private static final MyDoubleLockSingleton _mySingleton = new MyDoubleLockSingleton();

    //private constructor
    private MyDoubleLockSingleton() {
        // perform initialization here.
    }

    //  double lock singleton approach
    public static Object getSingleton() {
        return _mySingleton;
    }
}

答案 1 :(得分:1)

你最大的缺陷就是每次getSingleton()来电同步。

双重检查”锁定的想法是首先执行非同步检查。这适用于已经初始化单例的情况。 如果单例已存在,则没有理由同步

如果在执行非同步检查时单例为null,则表示同步:

public Singleton getSingleton() {
    if(singleton == null) {
        synchronized(lock) {

        }
    }
}

现在我们需要确保从我们离开空检查到我们进入同步块的时间没有其他线程可能已经初始化了单例。如果在那段时间内创建了单例,我们不想创建新的单例。这就是我们进行第二次空检查的原因:

public Singleton getSingleton() {
    if(singleton == null) {
        synchronized(lock) {
            if(singleton == null) {
                //create
            }
        }
    }
}

避免这种情况的更简单方法是使用Initialize-On-Demand习语:

class Singleton {
    private static final Singleton SINGLETON = new Singleton();

    public static Singleton getSingleton() {
        return SINGLETON;
    }
}

我们的想法是让处理静态初始化(已经同步)的机制为你处理创建。

更简单的替代方案是enum

public enum Singleton {
    INSTANCE;
}

为了减少冗长,我通常使用GET代替INSTANCE。这假设您没有使用静态导入,如果是这种情况,您应该使用更合适的名称。

答案 2 :(得分:0)

除了Vince提到的同步,以及在get singleton中返回对象之外它也很好。通常在singleton方法中称为instance或getInstance。删除构造函数的主体。可以使用单例模式但是如果可以的话尽量避免单例,否则当应用程序只有一个线程时,尽可能快地初始化它。一般规则 - 你拥有的单身越少越好。请参阅此文http://www.javaworld.com/article/2074979/java-concurrency/double-checked-locking--clever--but-broken.html

从文章看差异

class SomeClass {
  private Resource resource = null;
  public Resource getResource() {
    if (resource == null) {
      synchronized {
        if (resource == null) 
          resource = new Resource();
      }
    }
    return resource;
  }
}

class A {
  static private A a = null;
  public Resource instance() {
    if ( a == null ) {
      synchronized {
        if (a == null ) 
           a= new A();
      }
    }
    return a;
  }
}

答案 3 :(得分:0)

实际上有一种首选方法,也是最容易实现的方法。的枚举

  • 他们保证在JVM上只有一个实例
  • 他们是可序列化安全的
  • 他们是线程安全的

答案 4 :(得分:0)

你没有提到你的java版本,但这是我过去使用过的。我有一些代码应该像单身人士那样使用单一检查锁定,并且当报告线程相互冲突时,在负载下会混淆报告。我使用了这个解决方案:Intialize-On-Demand-Holder Class Idiom:

public class Singleton {
        // Private constructor. Prevents instantiation from other classes.
        private Singleton() { }

        /**
         * Initializes singleton.
         *
         * {@link SingletonHolder} is loaded on the first execution of {@link Singleton#getInstance()} or the first access to
         * {@link SingletonHolder#INSTANCE}, not before.
         */
        private static class SingletonHolder {
                private static final Singleton INSTANCE = new Singleton();
        }

        public static Singleton getInstance() {
                return SingletonHolder.INSTANCE;
        }
}

它有效地创建了一个线程安全的单例。