单例模式的三种解法
1、懒汉式:线程不安全
public class Singleton1{
private static Singleton1 instance=null;
private Singleton1(){}
public static Singleton1 getInstance(){
if(instance == null){
instance=new Instance()
}
return instance;
}
}
缺点:如果在多线程环境中,有多个线程同时运行“if(instance == null)”语句且条件成立,这意味着会创建多个instance实例,违背了单例模式准则。
2、懒汉式:线程安全
public class Singleton2{
private static Singleton2 instance=null;
private Singleton2(){}
public static synchronized Singleton2 getInstance(){
if(instance == null){
instance=new Instance()
}
return instance;
}
}
缺点:加锁过程非常耗时,效率低下
3、饿汉式:线程安全
public class Singleton3{
private static Singleton3 instance=new instance();
private Singleton3(){}
public static Singleton3 getInstance(){
return instance;
}
}
缺点:未实现延迟加载,类加载时就创建实例,容易造成内存浪费。
4、双检锁:线程安全
public class Singleton4{
private static volatile Singleton4 instance=null;
private Singleton4(){}
public static Singleton4 getInstance(){
if(instance == null){
synchronized(Singleton4.class){
if(instance == null){
instance=new Instance();
}
}
}
return instance;
}
}
优点:只在第一次创建时,试图加锁,提高了效率。volatile 关键字可以防止指令重排。
5、静态内部类:线程安全
public class Singleton5{
private static class SingleTonHolder{
private static final Singleton5 INSTANCE=new Instance();
}
private Singleton5(){}
public static final Singleton5 getInstance(){
return SingletonHolder.INSTANCE;
}
}
优点:比双检锁实现简单,使用类加载机制保证实例化时只有一个线程并实现延迟加载。
缺点:存在反射攻击或者反序列化攻击。
6、枚举:线程安全
public enum Singleton{
INSTANCE;
public void doSomething(){}
}
优点:实现单例模式的最佳方式,它不仅能避免多线程同步问题,而且还自动支持序列化机制,防止反序列化重新创建新的对象,绝对防止多次实例化。
缺点:jdk要求版本jdk1.5及以上,还未被广泛采用。
总结:一般情况下,不建议使用第 1 种和第 2 种懒汉方式,建议使用第 3 种饿汉方式。只有在要明确实现 lazy loading 效果时,才会使用第 5 种登记方式。如果涉及到反序列化创建对象时,可以尝试使用第 6 种枚举方式。如果有其他特殊的需求,可以考虑使用第 4 种双检锁方式