3 回答
TA贡献2016条经验 获得超9个赞
第一个是延迟加载,第二个是急切加载。也许您的应用程序从不调用单例,因此如果创建单例的新实例是消耗大量资源的操作,那么延迟加载会更好,因为它会在需要时创建新实例。
TA贡献1846条经验 获得超7个赞
您使用的第一种方法不是线程安全的。我会认为这是一个错误。
第二种方法更简单、线程安全、快速,并且如果您确保构造函数不会抛出愚蠢的异常,则正确。
如果您绝对需要更多逻辑,您可以使用第一种方法,必须确保使用互斥锁保护它。就像是:
public class MySingleton {
private static final Object mylock = new Object();
private static MySingleton instance;
public static MySingleton getInstance() {
synchronized(mylock) {
if (instance == null) {
instance = new MySingleton();
}
return instance;
}
}
}
显然代码更复杂,使用更多内存,速度更慢,你不能将变量声明为 final ...
这两种方法都会懒惰地初始化 Singleton。在 Java 中,所有变量初始化和静态构造函数都在使用类时由类加载器参与,而不是在代码开始时。如果您的代码路径从不调用 getInstance,则 Singleton 将永远不会被初始化。
就个人而言,我避免使用单例,但是当我使用它们时,总是在变量声明上立即分配。
更正 我进行了一些实验,结果发现类初始化与主线程的执行并行发生。它没有等待,就像我相信的那样。至少在一个非常简化的测试场景中,初始化是急切的,但是是异步的。
TA贡献1828条经验 获得超3个赞
这两种实现单例的方式在功能上有什么区别吗?
是的。如果在变量声明中使用初始化器,则在初始化类时会创建实例,即使该实例从未被访问过。如果您在getInstance()
方法中对其进行初始化,则仅在访问该实例时才创建该实例。这具有线程安全隐患。如果初始化实例很便宜并且没有持久的外部副作用,那么它并没有太大的区别,但情况可能并非总是如此。
第一种方法在技术上是否表现更好,因为它只在第一次需要时才被初始化,而不是在程序启动时?
如果您要在任何情况下使用实例,那么无论如何您都将在某个时候支付初始化它的成本,因此在这个意义上没有性能差异。但是,第一种方法的线程安全版本在第一次调用时会比第二种方法稍微贵一些,并且您将在每次后续调用时再次支付额外的开销。
添加回答
举报