java中的单例模式。 懒惰的初始化

public static MySingleton getInstance() { if (_instance==null) { synchronized (MySingleton.class) { _instance = new MySingleton(); } } return _instance; } 

1.上面的getInstance方法实现有缺陷吗? 2.这两种实现有什么区别。

 public static synchronized MySingleton getInstance() { if (_instance==null) { _instance = new MySingleton(); } return _instance; } 

我已经在stackoverflow中看到了很多关于单例模式的答案,但我发布的问题主要是知道在这种特殊情况下方法和块级别的’synchronize’的区别。

1.上面的getInstance方法实现有缺陷吗?

这是行不通的。 您最终可能会遇到Singleton的几个实例。

2.这两种实现有什么区别。

第二个工作,但需要同步,当您从不同的线程访问该方法时,这可能会减慢系统速度。

最直接的正确实现:

 public class MySingleton{ private static final MySingleton _instance = new MySingleton(); private MySingleton(){} public static MySingleton getInstance() { return _instance; } } 

更短更好(安全可序列化):

 public enum MySingleton{ INSTANCE; // methods go here } 

懒惰的单例初始化是一个让人注意与其实际实用性不成比例的话题(IMO争论双重检查锁定的复杂性,你的例子是第一步,只不过是一个小便竞赛)。

在99%的情况下,您根本不需要延迟初始化,或者Java的“首次引用类时初始化”就足够了。 在剩下的1%的情况下,这是最好的解决方案:

 public enum MySingleton{ private MySingleton(){} private static class Holder { static final MySingleton instance = new MySingleton(); } static MySingleton getInstance() { return Holder.instance; } } 

1.上面的getInstance方法实现有缺陷吗?

是的,synchronized关键字也应该包装if语句。 如果不是那么两个或多个线程可能会通过创建代码。

2.这两种实现有什么区别。

第二个实现是正确的,从我的角度来看更容易理解。

在方法级别使用synchronized为静态方法在类上进行同步,即您在示例中所做的事情1.在方法级别使用synchronized实例方法在对象实例上进行同步。

第一个是有两个方面的缺陷。 正如其他人提到的那样,multithreading可以通过

 if (_instance==null) { 

它们会相互等待,直到对象完全构造,但它们会进行实例化并替换变量中的引用。

第二个缺陷有点复杂。 一个线程可以进入构造函数new MySingleton() ,然后JVM切换到另一个线程。 另一个线程可以检查变量是否为null,但是可能包含对部分构造的对象的引用。 所以另一个线程适用于部分构造的Singleton,这也不好。 所以应避免使用第一个变体。

第二个变体应该可以正常工作。 不要太在意效率,直到你明确地将其识别为阻挡剂。 现代JVM可以优化掉不需要的同步,因此在实际的生产代码中,这种结构可能永远不会损害性能。

Bob Lee在Lazy Loading Singletons中讨论了延迟加载单例的各种方法,并且“正确”方法是初始化按需保持器(IODH)习语 ,其需要非常少的代码并且具有零同步开销。

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

Bob Lee还解释了他何时想要懒惰加载单例(在测试和开发期间)。 老实说,我不相信会有很大的好处。

第二个是线程安全的,但无论实例是否构造,它都会在每次调用时都有同步的开销。 第一个选项有一个主要缺陷,它没有检查synchronized块中的if(_instance == null)以防止创建两个实例。

我建议以下实施

 public class MySingleTon { private static MySingleton obj; //private Constructor private MySingleTon() { } public static MySingleTon getInstance() { if(obj==null) { synchronized(MySingleTon.class) { if(obj == null) { obj = new MySingleTon(); } } } return obj; } }