饿汉式
public class HungrySingleton {
private static final HungrySingleton hungrySingleton = new HungrySingleton();
public HungrySingleton() {
}
public static HungrySingleton getInstance() {
return hungrySingleton;
}
public void log() {
System.out.println("I am hungry");
}
}
饿汉式实现方式较为简单,假如加载的对象比较大,那么延迟加载不会是个好方法,所以饿汉式完全胜任。
但是假如说加载了个可有可无或者利用率非常低的方法,那么延迟加载就会出现
懒汉式
public class LazySingleton {
private LazySingleton lazySingleton;
private LazySingleton() {
}
public synchronized LazySingleton getInstance() {
if (lazySingleton == null) {
lazySingleton = new LazySingleton();
}
return lazySingleton;
}
}
那么,上面的实现有什么缺陷?
加了synchronized这把锁,不过有没有对象都会串行化执行,那么它的并行度趋近于1,假如这样会大大降低执行效率。
这时,双重检测机制就出现了。
懒汉式(双重检测)
public class LazySingleton {
private LazySingleton lazySingleton;
private LazySingleton() {
}
public LazySingleton getInstance() {
if (lazySingleton == null) {
synchronized (LazySingleton.class) {
if (lazySingleton == null) {
lazySingleton = new LazySingleton();
}
}
}
return lazySingleton;
}
}
如上实现所示,每次进入getInstance这个方法时,检测是否存在对象,再决定是否加锁,解决了synchronized串行化影响效率的问题。
静态内部类
public class StaticInnerClassSingleton {
static class Inner {
public static final StaticInnerClassSingleton staticInnterClassSingleton = new StaticInnerClassSingleton();
}
private StaticInnerClassSingleton() {
}
public static StaticInnerClassSingleton getInstance() {
return Inner.staticInnterClassSingleton;
}
}
使用静态内部类,既可以解决串行化影响效率,又可以延迟加载。实现方式简单。
枚举单例
enum EnumSingleton {
ENUM_SINGLETON;
public void log() {
System.out.println("I am ENUM_SINGLETON");;
}
}
单例模式的缺点
单例模式很多时候被认为是一种反模式的设计模式。
对OOP的支持不好
假如说用单例模式做一个ID生成器,UserID用IDGenerator,OrderID也用IDGenerator,有一天不同业务需要不同的IDGenerator,这样就会在User类中与Order类中大动干戈。
单例模式会隐藏调用关系
举个例子,假如说注入的方式去调用,可读性会变得很好,但是单例会隐藏各个依赖之间的调用关系,会降低可读性。
单例模式对代码的拓展性不友好
假如有一个数据库连接池使用了单例,短期看并没有问题,假如说突然变得很慢,需要加一个数据库连接池去做快SQL,这个慢SQL后台处理,这样做就会相当麻烦,因为单例模式的对象一初始化就无法变更内容。
单例模式不支持有参数的构造函数
解决方案1是:
使用init对象然后对单例模式进行传参
解决方案2是:
使用getInstance函数进行传参
当使用解决方案2解决的时候,发现一次初始化,再次传入参数时就无法变更里面的参数,
这样子的话可以在初始化构造方法的时候进行参数校验,看oldVal和newVal是否相等,
若不等就传新的进去。