Singleton模式结合了延迟加载和线程安全性

时间:2013-04-03 15:56:51

标签: java design-patterns singleton

我正在做一些关于单身人士的研究,特别是关于单身人士的懒惰与急切初始化。

热切初始化的一个例子:

public class Singleton
{
    //initialzed during class loading
    private static final Singleton INSTANCE = new Singleton();

    //to prevent creating another instance of Singleton
    private Singleton(){}

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

但如上所示,它是急切的初始化,线程安全留给jvm 但现在,我希望有相同的模式,但是懒惰的初始化。

所以我想出了这个方法:

public final class Foo {
    private static class FooLoader {
        private static final Foo INSTANCE = new Foo();
    }
    private Foo() {
        if (FooLoader.INSTANCE != null) {
            throw new IllegalStateException("Already instantiated");
        }
    }
    public static Foo getInstance() {
        return FooLoader.INSTANCE;
    }
}

如上所示,自行

private static final Foo INSTANCE = new Foo(); 

仅在实际使用类FooLoader时执行,它负责延迟实例化,并且保证是线程安全的。

这是正确的吗?

5 个答案:

答案 0 :(得分:20)

在我看来,你的第二个代码片段是线程安全的懒惰初始化单例的最佳方式。它实际上有一个模式名称

Initialization-on-demand holder idiom

我建议你使用它。

答案 1 :(得分:6)

你第一次设计实际上是懒惰的。想一想,实例只在初始化类时创建;只有在调用getSingleton()方法时才会初始化类[1]。因此,实例仅在被要求时创建,即它是懒惰创建的。

[1] http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4.1

答案 2 :(得分:2)

第二个在可读性方面非常差,第一个是合适的。看看这个article。它关于双重检查锁定,但也会为您提供有关单例多线程的广泛信息。

答案 3 :(得分:1)

最好的方法是使用Enum Way

public enum Singleton {
    INSTANCE;
    public void execute (String arg) {
            //... perform operation here ...
    }
}

答案 4 :(得分:0)

在我看来,这是一种不合适的模式。它对JVM的行为进行了假设,这些假设非常重要且令人困惑。此外,它有一个虚拟类。应尽可能避免使用虚拟课程。

我建议采用直截了当的方法:

public class Foo {
    private volatile static final Foo instance = null;

    private Foo() {
    }

    public static Foo instance() {
        if (instance == null) instance = new Foo();
        return instance;
        }
    }
}

...虽然,这不是原样的 - 它不是线程安全的..你真正想要的是Bloch的 Effective Java 的第71项中提出的复核模式;见here。根据您案例的链接调整示例,我们得到:

public class Foo {
    private volatile static final Foo instance = null;

    private Foo() {
    }

    public static Foo instance() {
        if (instance != null) return instance;
        synchronized(instance) {
           Foo result = instance;
           if (instance == null) {
                result = instance = new Foo();
           return result;
        }
    }
}

注意:

  • 不要担心这段代码的性能,现代JVM会处理它并且它很好。毕竟,premature optimization is the root of all evil
  • 正如其他答案中所建议的那样,上面不是Bloch的首选解决方案,但我认为使用单例的枚举在语义上是不合适的,就像OP最初的那样。