概念
- 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
- 这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
结构
单例模式的主要有以下角色:
- 单例类。只能创建一个实例的类
- 访问类。使用单例类
单例模式的实现
饿汉式
- 类加载的时候就会创建该单例对象
静态变量方式
- 实现过程

优点:简单
缺点:instance对象是随着类的加载而创建的,可能造成类加载的时候,同时对象在内存中创建,但是对象并不使用造成内存的浪费。单例模式一般是调用
getInstance方法的时候进行加载的,但也不排除其他加载的情况。
静态代码块
- 实现过程

其实和静态变量的原理是一样的,都是在
<clinit>()执行,完成静态变量的初始化
- 饿汉式的缺点:类在执行
<clinit>()方法的时候会对静态内容完成初始化,这个时候就在内存中创建对象了。
懒汉式
- 类加载不会导致该单例对象被创建,只有在首次使用的时候该对象才会被创建
线程不安全
- 实现

加入synchronized保证线程安全,但是每次getInstance都需要同步。也就是每次读操作都需要synchronized,这里是没必要的
- 优点:在使用的时候才完成初始化,在内存中创建对象
双重检查锁
- 实现

- 存在的问题:指令重排序
使用volatile修饰
- 添加
volatile关键字之后的双重检查锁模式是一种比较好的单例实现模式,能够保证在多线程的情况下线程安全也不会有性能问题。【推荐使用】
静态内部类
- 实现
由于 JVM 在加载外部类的过程中, 是不会加载静态内部类的, 只有内部类的属性/方法被调用时才会被加载, 并初始化其静态属性。静态属性由于被
static修饰,保证只被实例化一次,并且严格保证实例化顺序。
枚举方式
- 实现

破坏单例模式
使上面定义的单例类(Singleton)可以创建多个对象,枚举方式除外。有两种方式,分别是序列化和反射。
序列化和反序列化破坏单例模式
单例需要实现Serialable接口
- 反射破坏单例模式
将私有构造方法取消访问检查,这样就可以调用构造方法创建对象
解决单例模式被破坏
- 解决序列化方式创建的对象
在Singleton类中添加
readResolve()方法,在反序列化时被反射调用,如果定义了这个方法,就返回这个方法的值,如果没有定义,则返回新new出来的对象。
可以看到通过反序列化创建的是同一个对象
原理
如果是对象类
同样可以看到枚举类也有反序列化机制
进入到
readOrdinaryObject
查看如何判断是否有
readResolve()方法的
- 解决反射破坏单例模式
思路:多次调用构造方法抛出异常
JDK源码-Runtime类
- 经典饿汉式单例模式
















