下面的代码片段中有两个Singleton实现。 它们是在Java中的多线程环境中实现Singletons的正确方法吗?
如果是这样,这是否意味着第二种实现方式完全没用,而只要你想实现一个Singleton,只需使用枚举方式?
我编写Singleton的优先方式:
public enum Singleton {
INSTANCE();
}
编写Singleton的另一种方法(显式同步):
public class Singleton {
private static Singleton instance = null;
private Singleton() {}
public static synchronized Singleton getInstance() {
if (instanz == null) {
instanz = new Singleton();
}
return instanz;
}
答案 0 :(得分:2)
你们两种方法都很好看。但是,为了创建Singleton,我将建议以下方法,它是100%线程安全且没有同步问题,因为它利用了Java的类加载机制。
P.S。:对@james的触发信用。
懒惰的单身人士:
像这个类一样,Provider只会加载一次,因此只存在一个Network类实例,并且没有两个线程可以在同一个JVM中创建2个实例,因为类不会被加载两次。
优点:
getInstance()
时无需承担同步费用,这会在getInstance()
同步时发生。类中可以有其他静态方法,可以在不创建实例的情况下调用,只在需要实例方法调用时才创建实例。这是懒惰单身人士的一个很好的优势。
public class Network {
private Network(){
}
private static class Provider {
static final Network INSTANCE = new Network();
}
public static Network getInstance() {
return Provider.INSTANCE;
}
//More code...
}
渴望单身人士:
private static Network INSTANCE = null;
private Network(){
}
static {
INSTANCE = new Network();
}
public static Network getInstance() {
return INSTANCE;
}
最后:你说得对,你指定的第二种方法确实是最后一种选择,因为每次2个线程试图获取实例时,它必须承担同步的成本单身人士。
现在,它的ENUM单人v / s懒人单身游戏。我已经为你提供了很少的链接,说明为什么人们不喜欢单身人士的ENUM以及基于课程加载的ENUM单人v / s懒人单人的可扩展性。
这两种方法都可以无缝地工作,因此它的选择问题,因此真正的答案是"它取决于!!!" :)
答案 1 :(得分:2)
一些程序员讨论如何创建单例的原因是,他们希望支持延迟创建,但担心后续调用accessor方法的性能。
因此,使用synchronized
的类实现了延迟创建方面,但后续调用可能会受到synchronized
的不必要开销的影响。为了克服这个假设的开销,臭名昭着的双重检查锁定被发明,这引起了更多关于这个“问题”的讨论,这实际上完全无关紧要:
如果您想将懒惰创作与单例组合,您可以使用:
public class Singleton {
static final Singleton INSTANCE=new Singleton();
private Singleton(){}
public static Singleton getInstance() {
return INSTANCE;
}
}
整个构造是惰性的,因为类初始化不会在第一个线程调用getInstance()
之前发生并且它是线程安全的,因为类初始化本身保证是JVM的线程安全的。它是最有效的解决方案,因为后续调用只需读取final
字段而无需同步。
这正是使用
时会发生的事情public enum Singleton {
INSTANCE;
}
它可以避免声明private
构造函数,因为编译器会为您执行此操作。该字段隐含static final
。一个区别是该字段本身是暴露的,不需要访问方法。
此外,enum
支持序列化,本质上。存储常量时,不存储实例数据,只存储类型和常量名称。在反序列化时,将查找当前运行时实例。因此,如果您需要序列化支持,则应首选enum
,否则没有太大区别(使用enum
可以节省一些输入内容。)
但是
简单地说,单身人士设计模式似乎被高估了,并讨论了如何更有效地实施它......
答案 2 :(得分:0)
两者都是线程安全的,但是第一个使用枚举,避免了不必要的锁定,在大多数情况下更可取。
答案 3 :(得分:0)
第一个解决方案适用于创建singelton,因为您想要为某个事物建模。在此解决方案中,如果在创建未找到文件的实例期间发生异常,您将获得classnotfound异常。
第二种解决方案适用于创建singelton,因为对象的创建需要很长时间,并且涉及对文件系统或网络的访问。