设计模式之单例模式详细讲解(2种饿汉设计模式、4种懒汉设计模式、创建型设计模式、结构型设计模式、行为型设计模式)
前言
软件设计模式(Software Design Pattern),又称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。
本文是通过代码示例的方式,讲解单例模式。其他设计模式,参考下方《设计模式系列》。
本项目属于《设计模式系列》。点击下载完整代码示例:
- 《通过代码示例,讲解单例模式:2种饿汉模式的实现、4种懒汉模式实现、序列化和反射是如何破坏单例的、如何防止序列化和反射破坏单例》
- 《通过代码示例,讲解创建型模式:工厂方法模式、抽象工厂模式、原型模式、建造者模式》
- 《通过代码示例,讲解结构型模式:代理模式、适配器模式、装饰者模式、桥接模式、外观模式、组合模式、享元模式》
- 《通过代码示例,讲解行为型模式:模板方法模式、策略模式、命令模式、职责链模式、状态模式、观察者模式、中介者模式、迭代器模式、访问者模式、备忘录模式、解释器模式》
1 单例设计模式
单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
1.1 单例模式的结构
单例模式的主要有以下角色:
- 单例类。只能创建一个实例的类
- 访问类。使用单例类
1.2 单例模式的实现
单例设计模式分类两种:
饿汉式:类加载就会导致该单实例对象被创建
懒汉式:类加载不会导致该单实例对象被创建,而是首次使用该对象时才会创建
-
饿汉式-方式1(静态变量方式)
/** * 饿汉式 * 静态变量创建类的对象 */ public class Singleton { //私有构造方法 private Singleton() { } //在成员位置创建该类的对象 private static Singleton instance = new Singleton(); //对外提供静态方法获取该对象 public static Singleton getInstance() { return instance; } }
说明:
该方式在成员位置声明Singleton类型的静态变量,并创建Singleton类的对象instance。instance对象是随着类的加载而创建的。如果该对象足够大的话,而一直没有使用就会造成内存的浪费。
-
饿汉式-方式2(静态代码块方式)
/** * 恶汉式 * 在静态代码块中创建该类对象 */ public class Singleton { //私有构造方法 private Singleton() { } //在成员位置创建该类的对象 private static Singleton instance; static { instance = new Singleton(); } //对外提供静态方法获取该对象 public static Singleton getInstance() { return instance; } }
说明:
该方式在成员位置声明Singleton类型的静态变量,而对象的创建是在静态代码块中,也是对着类的加载而创建。所以和饿汉式的方式1基本上一样,当然该方式也存在内存浪费问题。
-
懒汉式-方式1(线程不安全)
/** * 懒汉式 * 线程不安全 */ public class Singleton { //私有构造方法 private Singleton() { } //在成员位置创建该类的对象 private static Singleton instance; //对外提供静态方法获取该对象 public static Singleton getInstance() { if(instance == null) { instance = new Singleton(); } return instance; } }
说明:
从上面代码我们可以看出该方式在成员位置声明Singleton类型的静态变量,并没有进行对象的赋值操作,那么什么时候赋值的呢?当调用getInstance()方法获取Singleton类的对象的时候才创建Singleton类的对象,这样就实现了懒加载的效果。但是,如果是多线程环境,会出现线程安全问题。
-
懒汉式-方式2(线程安全)
/** * 懒汉式 * 线程安全 */ public class Singleton { //私有构造方法 private Singleton() { } //在成员位置创建该类的对象 private static Singleton instance; //对外提供静态方法获取该对象 public static synchronized Singleton getInstance() { if(instance == null) { instance = new Singleton(); } return instance; } }
说明:
该方式也实现了懒加载效果,同时又解决了线程安全问题。但是在getInstance()方法上添加了synchronized关键字,导致该方法的执行效果特别低。从上面代码我们可以看出,其实就是在初始化instance的时候才会出现线程安全问题,一旦初始化完成就不存在了。
-
懒汉式-方式3(双重检查锁