总结一波单例设计模式的几种写法以及各自存在的优缺点。
1,饿汉式
顾名思义,实例对象早早的就创建出来了。这种方式在类加载的时候就完成了初始化,所以类加载过程比较缓慢,但是在使用过程中获取实例对象的速度比较快,也因为这种方式是基于类加载机制的,所以避免了多线程的同步问题。
public class SingleTon {
private static SingleTon instance = new SingleTon();
private SingleTon(){}
public static SingleTon getInstance(){
return instance;
}
}
优点:获取对象的速度快;避免了多线程的同步问题
缺点:类加载过程慢
2,懒汉式(线程不安全)
顾名思义,实例对象创建时间较晚。实例对象在用户第一次调用的时候初始化,虽然节约了资源,但是第一次加载时反应稍慢,而且在多线程的情况下不能正常使用。
public class SingleTon {
private static SingleTon instance;
private SingleTon() {}
public static SingleTon getInstance() {
if (instance == null) {
instance = new SingleTon();
}
return instance;
}
}
优点:节约资源
缺点:第一次加载时需要实例化,反应稍慢;多线程下不能正常工作
3,懒汉式(线程安全)
这种写法时线程安全的,在多线程情况下是可以正常工作的,但是每次获取实例对象的时候都需要进行同步,造成不必要的同步开销。在移动应用开发端用到同步的情况很少,所以不建议使用。
public class SingleTon {
private static SingleTon instance;
private SingleTon() {}
public static synchronized SingleTon getInstance() {
if (instance == null) {
instance = new SingleTon();
}
return instance;
}
}
优点:在多线程下可以安全的使用
缺点:造成不必要的同步开销
4,双重检查机制(DCL)
这种写法有两次判空。第一次判空是减少不必要的同步开销,也是对上面写法的改进;第二次判空是创建实例对象。注意这里使用了volatile关键字
public class SingleTon {
private static volatile SingleTon instance;
private SingleTon() {}
public static SingleTon getInstance() {
if (instance == null) {
synchronized (SingleTon.class) {
if (instance == null) {
instance = new SingleTon();
}
}
}
return instance;
}
}
优点:资源利用率高,线程安全
缺点:第一次加载时反应稍慢,在高并发环境下有缺陷
5,静态内部类
这种单例模式在第一次类加载时并不会初始化,只有在第一次调用getInstance();时虚拟机加载SingletonHolder并初始化SingleTon实例,也是线程安全的,也是推荐使用的。
public class SingleTon {
private SingleTon() {}
public static SingleTon getInstance(){
return SingletonHolder.instance;
}
private static class SingletonHolder{
private static final SingleTon instance = new SingleTon();
}
}
优点:线程安全,节约资源
缺点:第一次加载时反应稍慢