在Java中实现单例设计模式的有效方法是什么?


当前回答

创建单例对象的各种方法:

根据约书亚·布洛赫的说法,埃努姆将是最好的。也可以使用双重检查锁定。甚至可以使用内部静态类。

其他回答

Stu Thompson发布的解决方案在Java 5.0及更高版本中有效。但我宁愿不使用它,因为我认为它容易出错。

人们很容易忘记不稳定的说法,也很难理解为什么有必要这样做。如果没有易失性,由于双重检查锁定反模式,该代码将不再是线程安全的。有关这一点的更多信息,请参阅《Java并发实践》第16.2.4段。简而言之:此模式(在Java5.0之前或没有volatile语句)可能返回对Bar对象的引用,该对象(仍然)处于错误状态。

这种模式是为性能优化而发明的。但这真的不再是一个真正的问题了。下面的惰性初始化代码很快,更重要的是,更容易阅读。

class Bar {
    private static class BarHolder {
        public static Bar bar = new Bar();
    }

    public static Bar getBar() {
        return BarHolder.bar;
    }
}
public class Singleton {

    private static final Singleton INSTANCE = new Singleton();

    private Singleton() {
        if (INSTANCE != null)
            throw new IllegalStateException(“Already instantiated...”);
        }


    public synchronized static Singleton getInstance() {
        return INSTANCE;
    }

}

由于我们在getInstance之前添加了Synchronized关键字,因此在两个线程同时调用getInstance的情况下,我们避免了竞争条件。

创建单例对象的各种方法:

根据约书亚·布洛赫的说法,埃努姆将是最好的。也可以使用双重检查锁定。甚至可以使用内部静态类。

看看这篇文章。

Java核心库中的GoF设计模式示例

从最佳答案的“Singleton”部分,

Singleton(可由每次返回相同实例(通常是其本身)的创建方法识别)java.lang.Runtime#获取运行时间()java.awt.Desktop#getDesktop()java.lang.System#getSecurityManager()

您还可以从Java本机类本身学习Singleton的示例。

有时简单的“static Foo=new Foo();”是不够的。想想你想做的一些基本数据插入。

另一方面,您必须同步任何实例化单例变量的方法。同步本身并不坏,但它可能会导致性能问题或锁定(在非常罕见的情况下,使用本示例。解决方案是

public class Singleton {

    private static Singleton instance = null;

    static {
          instance = new Singleton();
          // do some of your instantiation stuff here
    }

    private Singleton() {
          if(instance!=null) {
                  throw new ErrorYouWant("Singleton double-instantiation, should never happen!");
          }
    }

    public static getSingleton() {
          return instance;
    }

}

现在会发生什么?类通过类加载器加载。在从字节数组解释类之后,VM立即执行静态{}-块。这就是全部秘密:静态块只被调用一次,即这个单类加载器加载给定包的给定类(名称)的时间。