单例设计模式
要点
-
某个类只能有一个实例
构造器私有化
-
必须自行创建这个实例
含有一个该类的静态变量来保存这个唯一的实例
-
必须向整个系统提供这个实例
对外提供获取该实例对象的方式
- 直接暴露
- 用静态变量的get方法获取
几种常见形式
饿汉式
直接创建对象,不存在线程安全问题
三种形式
-
直接实例化(简洁直观)
/** * 直接实例化,不管你是否需要这个对象都会创建 * 构造器私有化 * 自行创建,并且用静态变量保存 * 向外提供这个实例 * 强调这是一个单例,可以用final修饰 */ public class Singleton1 { public static final Singleton1 INSTANCE = new Singleton1(); private Singleton1() { } }
-
枚举式(最简洁)
/** * 枚举类型,表示该类型的对象是有限的 * 限定成一个,就成了单例 */ public enum Singleton2 { INSTANCE }
-
静态代码块(适合复杂实例化)
public class Singleton3 { private static final Singleton3 INSTANCE; static { /** *其他逻辑 / INSTANCE = new Singleton3(); } private Singleton3() { } }
懒汉式
延迟创建对象
三种形式
-
线程不安全(适用于单线程)
/** * @author lixi * @date 2021/3/18 10:54 * 构造器私有化 * 用静态变量保存 * 向外提供静态方法,获取这个实例对象 */ public class Singleton4 { private static Singleton4 instance; private Singleton4() { } public static Singleton4 getInstance() { if (instance == null) { instance = new Singleton4(); } return instance; } }
-
线程安全(适用于多线程)
public class Singleton5 { private static Singleton5 instance; private Singleton5() { } public static Singleton5 getInstance() { synchronized (Singleton5.class) { if (instance == null) { instance = new Singleton5(); } } return instance; } } //双重校验,效率更高 public class Singleton6 { private static Singleton6 instance; private Singleton6() { } public static Singleton6 getInstance() { if (instance == null) { synchronized (Singleton6.class) { if (instance == null) { instance = new Singleton6(); } } } return instance; } }
-
静态内部类(适用于多线程)
public class Singleton7 { /** * 在内部类被加载和初始化是,才会创建INSTANCE对象 * 静态内部类不会随着外部类的加载和初始化而初始化,是单独去加载和初始化 * 因为是在内部类加载和初始化时加载和初始化的,因此时线程安全的 */ private static class Inner { private static final Singleton7 INSTANCE = new Singleton7(); } private Singleton7() { } public static Singleton7 getInstance() { return Inner.INSTANCE; } }