单例模式定义和使用场景
定义:
这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
如何解决: 判断系统是否已经有这个单例,如果有则返回,如果没有则创建。
使用场景
- 1、要求生产唯一序列号。
- 2、WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
- 3、创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。
应用实例:
- 1、一个班级只有一个班主任。
- 2、Windows 是多进程多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行。
- 3、一些设备管理器常常设计为单例模式,比如一个电脑有两台打印机,在输出的时候就要处理不能两台打印机打印同一个文件。
缺点: 没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
几种常见的单例模式实现
懒汉方式
- 保证线程安全
- 防止指令重排序
- 双重检查优化
/** * 双重检查懒汉模式 */ public class SingletonLazy { private volatile static SingletonLazy instance; private SingletonLazy() { } public static SingletonLazy getInstance() { if (instance == null) { synchronized (SingletonLazy.class) { if (instance == null) { instance = new SingletonLazy(); } } } return instance; } }
饿汉方式
饿汉模式:是在类加载节点就完成了实例的初始化
类加载的3个阶段 (补充知识)
- 加载 -> 加载对应的二进制文件,并且在方法区创建对应的数据结构
- 链接 -> a. 验证,b. 准备,c. 解析
- 初始化 -> 给静态属性赋初始值
饿汉模式示例
public class SingletonHungry { //静态变量在类加载的时候进行赋值 private static SingletonHungry instance = new SingletonHungry(); private SingletonHungry() { } public static SingletonHungry getInstance() { return instance; } }
内部类方式
因为一个类只会被加载一次所以可以利用这个特征来初始化单实对象。
/** * 静态内部类方式 */ public class SingletonInner { static class InnerClass { private static SingletonInner instance = new SingletonInner(); } public static SingletonInner getInstance() { return InnerClass.instance; } private SingletonInner() { if (InnerClass.instance != null) { throw new RuntimeException("单例不允许有多个示例!"); } } }
枚举方式
枚举是一个单例的实力
public class SingletonEnum { private SingletonEnum() { } private enum SingletonInnerEnum { INSTANCE; private SingletonEnum instance; SingletonInnerEnum() { this.instance = new SingletonEnum(); } public SingletonEnum getInstance() { return instance; } } public static SingletonEnum getInstance() { return SingletonInnerEnum.INSTANCE.getInstance(); } }