
单例模式单例模式是java中最简单的设置模式之一,属于创建型设计模式,它提供了一种创建对象最佳方法. 这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建,这个类提供了一种访问其唯一的对象方式,可以直接访问,不需要实例化该类的对象;单例总结1, 单例类只有一个实例;2, 单例类必须自己创建自己的唯一实例;3, 单例类必须给所有其他对象提供这一实例;确保一个类仅有一个实例化,提供全局唯一访问点,主要解决了一个全局的类频繁的创建与销毁 ; 减少不必要的资源浪费;关键代码构造函数是私有的使用单例模式优点内存中一个类只有一个实例,减少了内存开销,尤其是频繁的创建和销毁实例;缺点没有接口,不能继承, 与单一职责原则冲突,只关心内部逻辑,不关心外面怎么实例化;单例模式集中实现方式饿汉式publicclassSingleton{privatestaticSingleton instancenewSingleton();privateSingleton(){}publicstaticSingletongetInstance(){returninstance;}}饿汉式在类加载时就实例化对了使用时直接调用 getInstance() 方法。这个模式为线程安全的在多线程并发模式下不会重复实例化对象。优点 效率高缺点 对象实例化过早浪费内存资源懒汉模式publicclassSingleton{privatestaticSingleton singleton;privateSingleton(){}publicstaticSingletongetInstance(){if(singletonnull){singletonnewSingleton();}returnsingleton;}}这种模式没有在加载时实例化对象而是在调用getInstance() 方法时实例化对象使用懒汉式是为了避免过早的实例化减少内存资源浪费。优点第一次调用才初始化避免内存浪费。缺点 只适合单线程线程不安全改进1 、懒汉式–引入synchronizedpublicclassSingleton{privatestaticSingleton singleton;privateSingleton(){}// 添加了synchronized 关键字,保证线程安全publicstaticsynchronized SingletongetInstance(){if(singletonnull){singletonnewSingleton();}returnsingleton;}}引入synchronized 关键字修饰getInstance() 方法是为了解决线程不安全问题。利用多线程同步机制然原先的线程不安全回归到线程安全。优点第一次调用才初始化避免内存浪费。缺点引入synchronized 会因为线程阻塞、切换会带一些不必要的开销从而降低了系统性能效率会降低。改进2、双检锁/双重校验锁publicclassSingleton{privatestaticvolatile Singleton singleton;privateSingleton(){}publicstaticSingletongetSingleton(){if(singletonnull){// 使用类锁synchronized(Singleton.class){if(singletonnull){singletonnewSingleton();}}}returnsingleton;}}对比改进1 可以看到synchronized不在修饰一个方法而是缩小到修饰代码块因为同步锁的范围越小性能影响就越小效率越高这里可以注意到修饰变量instance的关键字增加了volatile。这里volatile主要作用是提供内存屏障禁止指令重排序。现有t1、t2两个线程同时访问getInstance(),假设t1、t2都执行到A处。由于有同步锁只能有个1个线程获得锁假如t1拥有该同步锁t1执行到C处instace new Singleton()。将会做如下3步骤1.分配内存空间2.初始化3.将instance指向分配内存空间正常的执行顺序应为1-2-3。执行第3步时这时候的instance就不再是null了。但由于指令重排序的存在执行顺序有可能变化为1-3-2。当执行3的时候instance就不再是null但初始化工作有可能还没有做完。这时候如果t2获取锁执行的话就会直接获取有可能还没有初始化完成的instance。这样使用instance会引起程序报错。当然这也是极端情况下我尝试几次无法捕捉重现但并不意味着问题不存在。volatile当然还是要加的。A处if判断作用主要是防止过多是线程执行同步代码块如果是单例模式的话这里同步代码块只会被执行一次。B处if判断作用主要是防止多线程作用下重复实例化保证线程安全。这也被称为双重检查锁定。双重检查锁定属于一种兼顾线程安全和性能的实现。改进3、静态内部类publicclassSingleton{privateSingleton(){}privatestaticclassHolder{publicstaticSingleton instancenewSingleton();}publicstaticSingletongetInstance(){returnHolder.instance;// 执行Holder的初始化工作}}使用静态内部类也是懒汉模式的一种实现当调用ggetInstance()才会触发加载静态内部类从而初始化获取instance实例。利用静态内部类的加载机制来保证线程安全。枚举publicenumSingleton{INSTANCE;publicvoidwhateverMethod(){}}这种方式简洁,制动支持序列化机制,防止对此实例化,是实现单例模式最佳方法用枚举方式实现单例模式是目前比较推荐的。枚举方式的好处是1、线程安全2、防止反射出现多个实例3、防止反序列化出现多个实例。PS: 部分参考 https://juejin.im/post/58c2c6b10ce4630054655a1d