1、定义
1个类只有1个实例化对象,并且提供一个全局访问点。
2、作用
保证1个类只有1个对象,降低对象之间的耦合。
3、工作原理
- 类的构造方法变成私有方法
- 类内部对类进行实例化
- 类中定义静态公有方法提供该类的全局唯一访问点,返回该类实例化对象
- 外部通过调用全局唯一访问方法,获取该类实例化对象
4、优缺点
4.1 优点
- 提供对唯一实例的受控访问
- 节省系统资源,对于一些需要频繁创建和销毁的对象,单例模式能节省系统资源
4.2 缺点
- 单例类代码过于复杂的化,会违背单一职责原则
- 实例化的对象如果长时间不被利用,会被系统回收,导致对象状态丢失
5、实现方式
根据需求场景,分2大类、6种实现方式。
5.1 初始化单例类时即创建单例
- 饿汉式
- 枚举类型
5.2 按需、延迟创建单例
- 懒汉式(基础实现)
- 懒汉式(同步锁)
- 懒汉式(双重检验锁)
- 静态内部类
5.3 饿汉式 例子
class Singleton {
// 1. 加载该类时,单例就会自动被创建
private static Singleton ourInstance = new Singleton();
// 2. 构造函数 设置为 私有权限
// 原因:禁止他人创建实例
private Singleton() {
}
// 3. 通过调用静态方法获得创建的单例
public static Singleton newInstance() {
return ourInstance;
}
}
5.4 枚举类型 例子
public enum Singleton{
//定义1个枚举的元素,即为单例类的1个实例
INSTANCE;
// 隐藏了1个空的、私有的 构造方法
// private Singleton () {}
}
// 获取单例的方式:
Singleton singleton = Singleton.INSTANCE;
5.5 懒汉式(基本实现)例子
class Singleton {
// 1. 类加载时,先不自动创建单例
// 即,将单例的引用先赋值为 Null
private static Singleton ourInstance = null;
// 2. 构造函数 设置为 私有权限
// 原因:禁止他人创建实例
private Singleton() {
}
// 3. 需要时才手动调用 newInstance() 创建 单例
public static Singleton newInstance() {
// 先判断单例是否为空,以避免重复创建
if( ourInstance == null){
ourInstance = new Singleton();
}
return ourInstance;
}
}
5.6 懒汉式(同步锁)例子
// 写法1
class Singleton {
// 1. 类加载时,先不自动创建单例
// 即,将单例的引用先赋值为 Null
private static Singleton ourInstance = null;
// 2. 构造函数 设置为 私有权限
// 原因:禁止他人创建实例
private Singleton() {
}
// 3. 加入同步锁
public static synchronized Singleton getInstance(){
// 先判断单例是否为空,以避免重复创建
if ( ourInstance == null )
ourInstance = new Singleton();
return ourInstance;
}
}
// 写法2
// 该写法的作用与上述写法作用相同,只是写法有所区别
class Singleton{
private static Singleton instance = null;
private Singleton(){
}
public static Singleton getInstance(){
// 加入同步锁
synchronized(Singleton.class) {
if (instance == null)
instance = new Singleton();
}
return instance;
}
}
5.7 懒汉式(双重检验锁)
class Singleton {
private static Singleton ourInstance = null;
private Singleton() {
}
public static Singleton newInstance() {
// 加入双重校验锁
// 校验锁1:第1个if
if( ourInstance == null){ // ①
synchronized (Singleton.class){ // ②
// 校验锁2:第2个 if
if( ourInstance == null){
ourInstance = new Singleton();
}
}
}
return ourInstance;
}
}
// 说明
// 校验锁1:第1个if
// 作用:若单例已创建,则直接返回已创建的单例,无需再执行加锁操作
// 即直接跳到执行 return ourInstance
// 校验锁2:第2个 if
// 作用:防止多次创建单例问题
// 原理
// 1. 线程A调用newInstance(),当运行到②位置时,此时线程B也调用了newInstance()
// 2. 因线程A并没有执行instance = new Singleton();,此时instance仍为空,因此线程B能突破第1层 if 判断,运行到①位置等待synchronized中的A线程执行完毕
// 3. 当线程A释放同步锁时,单例已创建,即instance已非空
// 4. 此时线程B 从①开始执行到位置②。此时第2层 if 判断 = 为空(单例已创建),因此也不会创建多余的实例
5.8 静态内部类
class Singleton {
// 1. 创建静态内部类
private static class Singleton2 {
// 在静态内部类里创建单例
private static Singleton ourInstance = new Singleton();
}
// 私有构造函数
private Singleton() {
}
// 延迟加载、按需创建
public static Singleton newInstance() {
return Singleton2.ourInstance;
}
}
// 调用过程说明:
// 1. 外部调用类的newInstance()
// 2. 自动调用Singleton2.ourInstance
// 2.1 此时单例类Singleton2得到初始化
// 2.2 而该类在装载 & 被初始化时,会初始化它的静态域,从而创建单例;
// 2.3 由于是静态域,因此只会JVM只会加载1遍,Java虚拟机保证了线程安全性
// 3. 最终只创建1个单例