我正在做一些关于单身人士的研究,特别是关于单身人士的懒惰与急切初始化。
热切初始化的一个例子:
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时执行,它负责延迟实例化,并且保证是线程安全的。
这是正确的吗?
答案 0 :(得分:20)
答案 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;
}
}
}
注意: