2011-11-30 67 views
1

我已经实现了Singleton类如下:Singleton模式在多线程环境中是否存在问题?

public class Singleton { 

    private static Singleton instance = null; 


    private Singleton() { 
    } 

private synchronized static void createInstance() { 
    instance = new Singletone(); 
} 


    public static Singleton getInstance() { 
     if(instance == null){ 
      createInstance(); 
     } 
     return instance; 
    } 

} 

但我想知道这是否是一个正确的实现单例。 多线程环境中是否有任何问题。

+0

错字:它是_Singleton_而不是单数。是的,这不是一个线程安全的Singleton。 – zengr

+1

可能重复的[java单例线程安全](http://stackoverflow.com/questions/4965534/java-singleton-thread-safe) – zengr

+1

可能的重复:http://stackoverflow.com/questions/70689/efficient-way -to-implement -singleton-pattern-in-java –

回答

5

您的实施几乎是正确的。问题是它不是线程安全的。 2个独立的线程可以同时输入getInstance(),检查该实例是否为空,然后创建2个类的实例。这里是修复:

public static synchronized Singletone getInstance() { 
    if(instance == null){ 
     createInstance(); 
    } 
    return instance; 
} 

请注意字​​。

0

这是singleton模式的正确实现,虽然你并不真的需要一个createInstance方法;你可以在getInstance中直接插入。另外,它拼写为“Singleton”,最后没有“e”。

假设你可以在多线程环境中创建一个问题。如果两个帧指针同时进入getInstance,那么先输入的那个可以得到一个实例Singleton,而第二个会得到另一个实例。

这取决于你如何使用它。如果您在设置线程之前使用单例,则不会有任何问题。如果这是一个问题,你可以考虑首先初始化单例。您也可以通过在方法声明中使用​​关键字来解决此问题。

7
public enum Singleton { 
    INSTANCE; 
    private int val; 

    public int getVal() { 
     return val; 
    } 
} 

用法:

Singleton.INSTANCE.getVal(); 

这是,你必须支持ENUM的Java版本> 5.0的完美单。

也在Joshua Bloch的Effective Java中提到。一篇博客文章在这里:Enum Singleton

更新:
另外,请用单身,只有当你是100%肯定,你需要一个!它杀死了代码的可测试性!但是你不能避免在某些地方避免它,比如在工厂里。
但请不要滥用它,在任何你真正需要的地方使用它。了解它的用途。

+0

@Downvoter:小心解释一下吗? – zengr

+1

对不起,偶然downvoted,事实证明,我不能清除,所以这+1是下一个最好的事情。 –

-1

你的实现似乎很好。单个JVM中的多线程对于那种单例问题不是问题,但它会在集群(两个或多个JVM)中导致问题。

请参阅http://java.sun.com/developer/technicalArticles/Programming/singletons/了解这些问题。

哦,这是单身人士,而不是单身人士。 :)

+2

实际上,即使在单个JVM中,它也是** ** **可能***多线程问题。您的链接也涵盖了“由于错误同步导致的多个实例”。 – Boris

0

单身不是线程安全的。正是这个原因,Double-checked Locking被引入。

从Java SE 5及更高版本开始,您可以使用volatile您的静态实例。 Java VM将知道如何在多线程运行时正确处理单例。

更多关于Double-checked locking

+0

从包含的链接中可以看出:“这种技术存在许多微妙的问题,通常应该避免” –

0

对于惰性初始化实现(您的情况),应该同步getInstance()方法以确保线程安全。

public static synchronized Singleton getInstance() 

或者您可以简单地在类加载时已经线程安全地初始化它。

private static Singleton instance = new MySingleton(); 
2

除了上面的枚举之外,我遇到过的最好的机制称为静态初始化。有了这个,你就可以依靠Java的内存模型的保证,所以它可以始终工作。下面是从an answer to a different question一个片段演示了这一点:

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

Singleton实例的SingletonHolder类对象将要创建的第一次SingletonHolder.INSTANCE被调用。

Java内存模型保证静态代码(new Singleton())只能由一个线程执行。所以没有双重检查锁定(这不起作用),并没有不必要的同步。所有后续的调用都将获取该实例。