单例模式
作用:
节约内存开销,提高效率(性能),提高资源使用率。
特点:(判定一个类结构它使用了什么设计模式)
1、构造方法私有化;
2、定义静态方法返回 当前对象;
3、确保这个对象是唯一的;
4、确保序列化和反序列化操作的过程中同样保证同一个对象;
5、不允许有子类(该类是个太监类 -> 加 final 字段)
只要满足1-4条件就可判断为单利模式,第5点不是绝对的
角色划分:(2个角色)
角色一 - 调用者
角色二 - 单例类
也可为单例类一个角色
变种:
1、单例模式 ->恶汉式
/** * 单例模式 -> 恶汉式 * * 优点:安全(为你提前准备好,不管你用不用) * 缺陷:耗费内存 * 使用场景:确定是单线程的时候 */ public final class Singleton1 { private static Singleton1 instance = new Singleton1(); private Singleton1(){ } public static synchronized Singleton1 getSingleton(){ return instance; } }
2、单例模式 -> 懒汉式
/** * 单例模式 -> 懒汉式 * * 优点:性能高 -> 在一定程度上节约了内存(用到了才创建) * 缺点:多线程问题(并发) * 问题一:不加锁 - 多线程并发情况下,会创建多个对象 * 解决方案 - 加同步锁解决创建多个对象的问题 * 问题二:加同步锁之后 * 阻塞 - 100个线程访问这个对象,等待上一个线程用完才允许使用(耗费性能) * 使用场景:确定是单线程的情况下 */ public final class Singleton2 { private static Singleton2 instance; private Singleton2(){ } //这种情况下,并发时会创建多个对象 // public static Singleton2 getInstance(){ // if(instance == null){ // instance = new Singleton2(); // } // return instance; // } //加个同步锁,问题:阻塞 - 100个线程访问这个对象,等待上一个线程用完才允许使用(耗费性能) public static synchronized Singleton2 getInstance(){ if(instance == null){ instance = new Singleton2(); } return instance; } }
3、单例模式 -> 双重检查 -> 折中方案
/** * 单例模式 -> 双重检查 -> 折中方案 * * 优点:既能够保证创建的对象为单例对象,同时也保证了多线程的安全 * 问题:第一步 - 分析编译器编译过程 * Singleton instance = new Singleton(); * new instance对象的过程 ↓ * 1、分配内存(new); * 2、调用构造方法初始化参数(Singleton()); * 3、将instance对象指向这块内存区域(内存空间)。 * 问题 - 双重检查会失败(失效) * 因为在Java虚拟机(JVM 1.5 之前)中Cache、寄存器到主内存回写数据顺序很有可能会乱序, * 有可能是 1-2-3(先初始化,再指向内存), * 也有可能是 1-3-2(先指向空内存,再初始化,由于为null就会创建所以可能会创建多个对象), * 最终导致程序报错。 * 解决方案 - 在Java虚拟机(JVM)1.5版本以及之后版本,做了优化关键字volatile * volatile含义:去掉虚拟机优化代码,直接 1-2-3 (Cache、寄存器属于优化代码) * 第二步 - 消耗性能(某些场景下可以忽略不计) * 略过了 Cache、寄存器就会降低性能 * 为了提高代码稳定性、程序正确性,会消耗性能。(权衡) * 使用场景:使用并没有进行优化过编译器或者共享内存处理器的情况下可以正常运行。 */ public final class Singleton3 { // private static Singleton3 instance; private static volatile Singleton3 instance; private Singleton3() { } public static Singleton3 getInstance() { if (instance == null) { // 同步代码块 - 如果为null创建,不为null直接返回 synchronized (Singleton3.class) { instance = new Singleton3(); } } return instance; } }
4、单例模式 -> 静态内部类 -> Java官方推荐
/** * 单例模式 -> 静态内部类 -> 多线程情况下使用合理一些 -> Java官方推荐 * * 优势: 既能够保证内存的优化,同时也能够保证单例对象的安全 * 当调用 Singleton4Holder 这个类的时候 Singleton4 就已经存在了,不会存在多线程问题。 * 使用场景:多线程情况下 */ public final class Singleton4 { private Singleton4(){ } public static Singleton4 getInstance(){ //当调用 Singleton4Holder 这个类的时候 Singleton4 就已经存在了,就不会存在多线程问题。 return Singleton4Holder.singleton4; } public static class Singleton4Holder{ private static Singleton4 singleton4 = new Singleton4(); } }
看以上的情况 一般单线程使用 懒汉式,多线程就使用 静态内部类的模式。