一、单例模式概念
单例模式(singleton pattern):是一种常用的软件设计模式。在它的核心结构中包含一个被称为单例的特殊类。应用该模式的类只能产生一个对象的实例。
二、单例模式的应用场景
四、单例模式的优点:
4.1.由于单例模式只能生成一个实例,减少了系统性能开销,当一个对象的产生需要比较多的资源时,如读取配置、产生其它依赖对象时,则可以通过在应用启动时产生一个单例对象,然后永久驻留内存的方式来解决。
4.2单例模式可以在系统设置全局访问点,优化共享资源访问,例如可以设计一个单例类,负责所有数据表的映射处理。
package edu.aeon.model.singleton; /** * 单例模式:饿汉式(类装载时创建) * 步骤: * 1.构造器私有化(防止外部new) * 2.提供静态的、私有的代表该对象的实例 * 3.提供静态的、公开的函数(方法)供外部访问应用该模式唯一实例 * @author aeon */ public class HungrySingleton { //1.构造器私有化(防止外部new) private HungrySingleton(){}; //2.提供静态的、私有的代表该对象的实例 private static HungrySingleton hungrySingletonInstance=new HungrySingleton(); //3.提供静态的、公开的函数(方法)供外部访问应用该模式唯一实例 public static HungrySingleton getSinletonInstance(){ return hungrySingletonInstance; } }
package edu.aeon.model.singleton; /** * 单例模式:懒汉式(类装载及创建) * 步骤: * 1.构造器私有化(防止外部new) * 2.提供静态的、私有的代表该对象的实例的空引用 * 3.提供静态的、公开的函数(方法)供外部访问 * @author aeon */ public class LazySingleton { //1.构造器私有化(防止外部new) private LazySingleton(){} //2.提供静态的、私有的代表该对象的实例的空引用(调用时才给值) private static LazySingleton lazySingletonInstance=null; //3.提供静态的、公开的函数(方法)供外部访问应用该模式唯一实例 public static LazySingleton getLazySingletonInstance(){ if(null==lazySingletonInstance){ lazySingletonInstance=new LazySingleton(); } return lazySingletonInstance; } }
两方方式的区别:
饿汉式:天然线程安全、调用效率高、不能延时加载、资源利用率低(有可能永远不会利用这资源)。
懒汉式:线程安全、调用效率低、可延时加载、资源利用效率高。
六、单例模式之懒汉式进化(主要适应高并发引发的线程安全问题)
6.1排队、加锁(synchronized)
package edu.aeon.model.singleton; /** * 单例模式:懒汉式(类装载及创建) * 步骤: * 1.构造器私有化(防止外部new) * 2.提供静态的、私有的代表该对象的实例的空引用 * 3.提供静态的、公开的函数(方法)供外部访问 * @author aeon */ public class LazySingleton { //1.构造器私有化(防止外部new) private LazySingleton(){} //2.提供静态的、私有的代表该对象的实例的空引用(调用时才给值) private static LazySingleton lazySingletonInstance=null; //3.提供静态的、公开的函数(方法)供外部访问应用该模式唯一实例 public static synchronized LazySingleton getLazySingletonInstance(){ if(null==lazySingletonInstance){ lazySingletonInstance=new LazySingleton(); } return lazySingletonInstance; } }
由于6.1使用了方法上的加锁、多线程访问时都要在该方法上进行排队等待、所以效率非常低。
6.2双重检查锁
package edu.aeon.model; /** * [说明]:单例模式_双重检查锁(不建议使用) * 步骤: * 1.构造私有化 * 2.提供静态私有的单例实例属性 * 3.提供静态公开的函数(方法)返回这个实例供外部访问 * @author aeon * */ public class SingletonDCL { //1.构造私有化 private SingletonDCL() {} //2.提供静态私有的单例实例属性 private static SingletonDCL singletonDCL = null; //3.提供静态公开的函数(方法)返回这个实例供外部访问 public static SingletonDCL getInstance() { if (singletonDCL == null) { SingletonDCL sdcl; synchronized (SingletonDCL.class) { sdcl = singletonDCL; if (sdcl == null) { synchronized (SingletonDCL.class) { if (sdcl == null) { sdcl = new SingletonDCL(); } } singletonDCL = sdcl; } } } return singletonDCL; } }
由于6.2的双重检查锁模式将同步内容下方到if内部,提高了执行的效率,不必每次获取对象时都进行同步,只有第一次才同步、创建了以后就没必要了,因为创建之后就不会进入if条件了、直接返回该唯一实例。
缺点:由于编译器优化原因和JVM底层内部模型原因,偶尔会出现问题,所以不建议使用。
6.3静态内部类(推荐)
package edu.aeon.model.singleton; /** * 单例模式:懒汉式(类装载及创建)进化(主要适应高并发下引发的线程安全问题) * 步骤: * 1.构造器私有化(防止外部new) * 2.提供静态内部类创建实例(JVM自动加锁、线程安全、只加载一次) * 3.提供静态的、公开的函数(方法)供外部访问 * @author aeon */ public class LazySingleton { //1.构造器私有化(防止外部new) private LazySingleton(){} //2.提供静态内部类创建实例(JVM自动加锁、线程安全、只加载一次) private static class temp{ private static final LazySingleton lazySingletonInstance=new LazySingleton(); } //3.提供静态的、公开的函数(方法)供外部访问应用该模式唯一实例 public static synchronized LazySingleton getLazySingletonInstance(){ return temp.lazySingletonInstance; } }
外部类没有static属性,则不会像饿汉式那样立即加载对象。
只有真正调用时,才会加载静态内部类。加载类时是线程安全的。该实例是static final类型的,从而保证了内存中只有这样一个实例的存在,而且只能被赋值一次,从而保证了线程安全性。
兼备了并发高效调用和延迟加载的优势,可谓单例模式中的"高富帅",集各种优势与一身啊、所以静态内部类实现的单例模式是特别推荐使用的。
6.4使用枚举实现单例
package edu.aeon.model; /** * [说明]:枚举实现单例模式(枚举本身就是单例) * @author aeon */ public enum SingletonEnum { singletonEnumInstance; /** * 实现一些其它的操作 */ public void otherOperator(){ //... } }
优点:
实现简单
枚举本身就是单例模式。由JVM从根本上提供保障避免了通过反射和反序列化的漏洞!
缺点
唯一不足就是没有延迟加载。