线程安全在Java中实现单例模式的有效方法?

问题描述:

可能重复:
Efficient way to implement singleton pattern in Java线程安全在Java中实现单例模式的有效方法?

我读这个Best Singleton Implementation In Java,但它不是线程安全的。

按照维基:

if(singleton==null) { synchronized(Singleton.class) { // this is needed if two threads are waiting at the monitor at the // time when singleton was getting instantiated if(singleton==null) singleton= new Singleton(); }
}

,但发现错误效用给出了这样两个错误: 1.双击空检查。 2.静态字段的延迟初始化不正确。

什么是最好的方式,

是否正确:

synchronized (Singleton.class) { 
if (singleton== null) { 
singleton= new Singleton(); 
} 
} 
+1

这是上述问题的重复;看到这个问题的细节。但我不确定这个问题是否有这些有用的链接,因此:[关于Java中的双重检查锁定](http://www.ibm.com/developerworks/java/library/j-dcl.html)链接到[这些](http://www.ibm.com/developerworks/library/j-jtp02244.html)[two](http://www.ibm.com/developerworks/library/j-jtp03304/)针对Java的更新另见[*关于双重锁定的文章](http://en.wikipedia.org/wiki/Double-checked_locking)。但是对于您的问题的实际答案,请参阅上面链接的问题。 – 2010-12-19 10:52:02

最有效的/最简单的方法,使延迟加载辛格尔顿只是

enum Singleton { 
    INSTANCE 
} 

注意:因为类加载是线程安全的,所以不需要锁定。该类默认是final,并且构造函数不能通过反射调用。 INSTANCE不会被创建,直到INSTANCE或该类被使用。如果您担心课程可能会被意外使用,您可以将单身人士包装在内部课程中。

final class Singleton { 
    private Singleton() { } 
    static class SingletonHolder { 
     static final Singleton INSTANCE = new Singleton(); 
    } 
    public static Singleton getInstance() { 
     return SingletonHolder.INSTANCE; 
    } 
} 

恕我直言,你必须是相当偏执,认为这是一个更好的解决方案。

+0

在你的第二个代码中,你没有使用'enum',但是你正在使用'class',所以我很困惑如何使用它。我想创建一个枚举来初始化一个类,并在下一次调用该对象。我该怎么做。请给出一个例子详细说明 – manish 2014-02-02 10:31:11

+0

@Manish在这种情况下,使用'enum'就像我在第一个例子。 – 2014-02-02 10:32:47

+0

嗯,没问题,但是我怎样才能初始化一个类,并在下一次使用'enum'时使用这个实例。这是我的困惑。每一个我只看到'枚举Singleton { INSTANCE }这么多,但不是如何调用和初始化对象 – manish 2014-02-02 10:35:12

Efficient way to implement singleton pattern in Java的接受答案中的第一个代码示例是线程安全。第一次加载类时,类加载器将执行INSTANCE的创建;它精确的进行一次,并在一个线程安全的方式:

public final class Foo { 

    private static final Foo INSTANCE = new Foo(); 

    private Foo() { 
     if (INSTANCE != null) { 
       throw new IllegalStateException("Already instantiated"); 
     } 
    } 

    public static Foo getInstance() { 
     return INSTANCE; 
    } 
} 

(从What is an efficient way to implement a singleton pattern in Java?复制)

在问题中的第二个代码示例是正确的,线程安全的,但它会导致在每次调用同步到getInstance(),这会影响性能。

+0

不保护私有构造函数是相当偏执的。我假设它避免使用反射创建另一个实例,或者它是否阻止调用构造函数的内部类? – 2010-12-19 10:48:55

+0

我正在讨论上一个问题的答案,所以我照原样复制了代码。我个人会忽略'if(INSTANCE!= null)'检查。 – 2010-12-19 10:52:07

+0

并因此我假设有例外情况。 ;) – 2010-12-19 13:05:41

关于这个问题已经写了很多。是的,简单的双重检查锁定模式并不安全。但是,通过将静态实例声明为volatile,可以使其安全。新的Java内存模型规范在处理volatile时为编译器添加了一些代码重新排序限制,因此原始风险已经消失。

反正我在创建实例时,很少真正需要这种lazyness的,所以我通常只是在类加载时静态创建它:

private static MyClass instance = new MyClass(); 

这是短暂的,明确的。作为替代方案,如果你真的想使懒惰,你可以利用的类加载的特性,做这样的:

public class MyClass { 
    private static class MyClassInit { 
     public static final MyClass instance = new MyClass(); 
    } 

    public static MyClass getInstance() { 
     return MyClassInit.instance; 
    } 
... 
} 

嵌套类不会被()第一次加载直到调用的getInstance。