单例模式
1.定义:
确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
2.使用场景:
确保某个类有且只有一个对象的场景,避免产生过多的对象消耗过多的资源,或者某种类型的对象只应该有且只有一个。
3.UML图
4.详解:
4.1饿汉模式
这种模式再类加载时就完成了初始化,所以加载较慢,但获取对象的速度快。
这种方式机遇类加载机制,避免了多线程的问题。在类加载的时候,就完成了实例化,没有达到懒加载的效果。如果至始至终都没有用到这个对象,则会造成内存的浪费。
public class Singleton0 {
private static Singleton0 instance = new Singleton0();
private Singleton0() {
}
public static Singleton0 getInstance() {
return instance;
}
}
4.2懒汉模式(线程不安全)
懒汉模式声明了一个静态对象,在用户第一次调用时初始化,节约了资源,
但第一次加载时需要实例化,反应稍慢一些,而且在多线程时不能正常工作。
public class Singleton1 {
private static Singleton1 instance;
private Singleton1() {
}
public static Singleton1 getInstance() {
if (instance == null) {
instance = new Singleton1();
}
return instance;
}
}
4.3懒汉模式(线程安全)
这种写法能做多线程中很好的工作,但是每次调用getInstance时,都需要进行同步,
这会造成不必要的同步开销,而且大部分时候,我们是用不到同步的,所以,不建议使用这种模式。
public class Singleton2 {
private static Singleton2 instance;
private Singleton2() {
}
public static synchronized Singleton2 getInstance() {
if (instance == null) {
instance = new Singleton2();
}
return instance;
}
}
4.4双重检查模式(DCL)
这种写法对Singleton3进行了两次判空,第一次是为了不必要的同步,第二次是在Singleton3为null的情况下才创建实例,在这里使用volatile会或多或少的影响性能,但考虑到程序的正确性,牺牲这点性能还是值得的。DCL的优点是资源利用率高,第一次执行getInstance时单例对象才能被实例化,效率高;缺点是第一次加载时反应稍慢一些,在高并发环境下也有一定的缺陷。DCL虽然在一定程度上解决了资源的消耗和多余的同步、线程安全等问题,但其还是在某些情况会出现失效的问题,也就是DCL失效。
public class Singleton3 {
private volatile static Singleton3 instance;
private Singleton3() {
}
public static synchronized Singleton3 getInstance() {
if (instance == null) {
synchronized (Singleton3.class) {
if (instance == null) {
instance = new Singleton3();
}
}
}
return instance;
}
}
4.5静态内部类单例模式
第一次加载Singleton4类时,并不会初始化sInstance,只有第一次调用getInstance时,虚拟机才会加载SingletonHolder并初始化sInstance,这样不仅能确保线程安全,也能保证Singleton4类的唯一性。所以推荐使用静态内部类单例模式。
public class Singleton4 {
private Singleton4() {
}
private static Singleton4 instance;
public static Singleton4 getInstance() {
return SingletonHolder.sInstance;
}
private static class SingletonHolder {
private static final Singleton4 sInstance = new Singleton4();
}
}
4.6枚举单例
public enum Singleton5 {
INSTANCE;
public void doSomething() {
//to do something
}
}