什么是单例模式
单例模式是确保一个类只有一个对象实例,并提供访问它的全局访问点。
常用于工具类或需要控制实例数量节省资源的场景。
单例模式的实现关键是构造方法私有,并提供一个获取唯一对象的接口。
单例模式有五种实现方式:懒汉式、饿汉式、双重校验锁(DCL)、静态内部类(推荐使用)、枚举。
饿汉式
为啥叫饿汉式的单例模式了?
这是因为饿汉式的单例模式会在类加载时就创建唯一实例,跟个饿汉似的上来就吃。
public class Singleton {
// 唯一实例
private static Singleton instance = new Singleton();
private Singleton (){ }
public static Singleton getInstance() {
return instance;
}
}
懒汉式
那懒汉式为啥又叫懒汉式了?
懒汉式就是懒啊,他得在要使用的时候才会初始化唯一实例。
//线程不安全的懒汉式
public class Singleton {
// 唯一实例
private static Singleton instance;
private Singleton (){ }
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
//线程安全的懒汉式
public class Singleton {
private static Singleton instance;
private Singleton (){ }
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
双重校验锁DCL(重点)
public class Singleton {
//唯一实例
//使用volatile避免指令重排序问题(重点)
private volatile static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
//同步会造成性能下降,在同步前通过判读instance是否初始化,减少不必要的同步开销。(重点)
if (instance== null) {
synchronized (Singleton.class) {
//(重点)
//如果不在这里加一个为空判断,则可能在第一个为空判断时进来多个对象,然后依次使用同步代码块创建多个对象
if (instance== null) {
//延迟初始化
instance= new Singleton();
}
}
}
return singleton;
}
}
什么是重排序问题
Java代码到运行会经过三次重排序,是一种优化机制。instance= new Singleton();经过编译后会分为三步1:分配内存空间 2:初始化对象 3:设置instance指向刚排序的内存空间。发生重排序,步骤变为1->3->2。线程A调用getsingleton方法执行到第3步时,线程B调用getInstance方法,在判断instance==null时不为null,则返回instance。但此时instance并还没初始化完毕,线程B访问的将是个还没初始化完毕的对象。
静态内部类(推荐使用)
public class Singleton {
private Singleton(){}
public static Singleton getInstance(){
return SingletonHolder.sInstance;
}
private static class SingletonHolder {
private static final Singleton sInstance = new Singleton();
}
}
怎么做到线程安全的?
JVM在执行类的初始化阶段,会获得一个可以同步多个线程的对同一个类初始化的锁。
枚举
public enum Sington{
INSTANCE;
private xxx instance;
private Sington(){ }
public static xxx getInstance(){
return instance;
}
}
| 是否延迟初始化 | 是否多线程安全 | 实现难度 | 优点 | 缺点 | |
|---|---|---|---|---|---|
| 饿汉式 | 否 | 是 | 易 | 没有加锁,执行效率会提高 | 类加载时就初始化,浪费内存 |
| 懒汉式 | 是 | 是 | 易 | 第一次调用才初始化,避免内存浪费 | 必须加锁 synchronized 才能保证单例,但加锁会影响效率。 |
| 双重校验锁 | 是 | 是 | 较复杂 | 采用双锁机制,安全且在多线程情况下能保持高性能 | 代码复杂 |
| 静态内部类 | 是 | 是 | 一般 | 实现代码简洁、延迟初始化、线程安全 | 相当好啊 |
| 枚举 | 否 | 是 | 易 | 能避免多线程同步问题,而且还自动支持序列化机制 | 因为JDK1.5才加入枚举,使用起来感觉陌生 |
本文深入解析单例模式的原理及五种实现方式:饿汉式、懒汉式、双重校验锁、静态内部类和枚举。探讨每种方式的特点、优缺点及适用场景。
1517

被折叠的 条评论
为什么被折叠?



