我有两个选择:
单身人士模式
class Singleton{
private static Singleton singleton = null;
public static synchronized Singleton getInstance(){
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
使用static final
字段
private static final Singleton singleton = new Singleton();
public static Singleton getSingleton() {
return singleton;
}
区别是什么? (单线程或多线程)
更新:我知道Bill Pugh或enum
方法。
我不是在寻找正确的方法,但我只使用过1.在1或2中是否有任何差异?
答案 0 :(得分:10)
主要区别在于,使用第一个选项时,单例只会在调用getInstance
时初始化,而使用第二个选项时,只要加载包含类,它就会被初始化。
懒惰且线程安全的第三个(首选)选项是使用枚举:
public enum Singleton {
INSTANCE;
}
答案 1 :(得分:2)
有一点不同:
解决方案1是一个延迟初始化,将在第一次调用getInstance
时创建单例实例
解决方案2是一个急切的初始化,单个实例将在类loades
时创建它们都是线程安全的,调用第二个多线程是一个有点误导性的
答案 2 :(得分:2)
第一种解决方案似乎更懒惰,但实际上并非如此。
第一次访问静态方法/字段时会初始化类。
getInstance()
可能是该类唯一可公开访问的静态方法/字段。这就是单身人士的观点。
然后,当有人第一次呼叫getInstance()
时,该类会被初始化。这意味着两种解决方案在懒惰方面基本相同。
当然,第二种解决方案看起来更好,性能更好。
答案 3 :(得分:1)
因此,通过更新,上述两个选项都是线程安全的。但是synchronized
选项要求每个调用instance
的线程获取此锁,从而降低性能(如果这样做很多)。此外,在方法级别使用synchronized
可能存在使用公共可用锁(类本身)的问题,因此如果某个线程获得此锁(可能),则可能最终导致死锁。 static final
选项性能更高,但不会对单例进行延迟初始化(根据系统的不同,这可能不是问题)。
允许Singleton的线程安全延迟初始化的另一个选项如下:
public class MySingleton{
private static class Builder{
private static final MySingleton instance = new MySingleton();
}
public static MySingleton instance(){
return Builder.intance;
}
}
这是有效的,因为静态内部类被保证在执行包含类中的任何方法之前被初始化。
答案 4 :(得分:-1)
Java中的Singleton实现(如果你真的想要的话)可以比你描述的eager和lazy初始化更优雅的方式执行。检查Joshua Bloch描述的the enum way和Bill Pugh提出的the SingletonHolder solution。
维基百科文章也是理解模式的良好开端,并且可以回答您的问题。