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; } }