一、概述
单例模式的定义为:确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。单例模式是一种对象创建型模式。
单例模式有三个要点:一是某个类只能有一个实例;二是它必须自行创建这个实例;三是它必须自行向整个系统提供这个实例。
单例模式结构图:

二、代码设计
单例类的内部实现只生成一个实例,同时提供一个静态的getInstance()方法,让客户可以访问它的唯一实例;为了防止在外部对其实例化,将其构造函数设计为私有;在单例类内部定义了一个Singleton类型的静态对象,作为外部共享的唯一实例。
1 | public class Singleton { |
三、单例分类
1. 饿汉式单例
饿汉式单例结构图:

典型代码如下:
1 | public class EagerSingleton { |
当类被加载时,静态变量instance会被初始化,此时类的私有构造函数会被调用,单例类的唯一实例将被创建。饿汉式单例不会出现创建多个单例对象的情况,可确保单例对象的唯一性。
2. 懒汉式单例
懒汉式单例结构图:
懒汉式单例在第一次调用getInstance()方法时实例化,在类加载时并不自行实例化,这种技术又称为延迟加载(Lazy Load)技术,即需要的时候再加载实例,为了避免多个线程同时调用getInstance()方法,可以使用关键字synchronized。
1 | public class LazySingleton { |
每次调用getInstance()时都需要进行线程锁定判断,在多线程高并发访问环境中,将会导致系统性能大大降低。
3. 双重检查锁定懒汉式
1 | public class LazySingleton { |
如果使用双重检查锁定来实现懒汉式单例类,需要在静态成员变量instance之前增加修饰符volatile,被volatile修饰的成员变量可以确保多个线程都能够正确处理。
4. 饿汉式与懒汉式的比较
饿汉式单例类在类被加载时就将自己实例化,其优点在于无须考虑多线程访问问题,可以确保实例的唯一性;由于单例对象一开始就得以创建,因此调用速度和反应时间速度都优于懒汉式单例。但是无论系统在运行时是否需要使用该单例对象,由于在类加载时该对象就需要创建,因此从资源利用效率角度来讲,饿汉式单例不及懒汉式单例,而且在系统加载时由于需要创建饿汉式单例对象,加载时间可能会比较长。
懒汉式单例类在第一次使用时创建,无须一直占用系统资源,实现了延迟加载,但是必须处理好多个线程同时访问的问题。
总结下来:饿汉式单例不能实现延迟加载,不管将来用不用始终占据内存;懒汉式单例类线程安全控制繁琐,且性能受影响。
四、IoDH(Initialization Demand Holder)
在单例类中增加一个静态内部类,在该内部类中创建单例对象,再将该单例对象通过getInstance()方法返回给外部使用。
1 | public class Singleton { |
通过使用IoDH,既可以实现延迟加载,又可以保证线程安全,不影响系统性能。
三、demo
办理身份证,第一次办理则设置证件号码,否则提示重复办理。
1 | public class IdentityCardNo { |