概述
单例模式属于创建型模式,保持对象实例在一个jvm内唯一,节省有限的资源消耗。
推荐单例的创建方式:
- 线程安全
- 懒加载
- 调用效率高(不用加锁)
思路
- 私有构造函数
- 私有静态实例
- 对外暴露公共的静态方法获取静态实例
类图
创建方式(5种)
- 饿汉式(非懒加载)
/**
* 饿汉式单例模式(在类加载的时候对实例进行初始化,导致没有调用 getSingleton() 时也占用了内存)
* 特点:线程安全、非懒加载、效率高
*/
public class SingletonHungry {
private static final SingletonHungry singleton = new SingletonHungry();
private SingletonHungry() {}
public static SingletonHungry getSingleton() {
return singleton;
}
}
- 懒汉式(加锁调用效率低)
/**
* 懒汉式单例模式
* 特点:线程安全、懒加载、效率低
*/
public class SingletonLazy {
private static SingletonLazy singleton;
private SingletonLazy() {}
// 线程安全,但每次调用需要加锁,效率低
public static synchronized SingletonLazy getSingleton() {
if (null == singleton) {
singleton = new SingletonLazy();
}
return singleton;
}
}
- 双重检查加锁(推荐)
/**
* 双重检查加锁
* 特点:线程安全、懒加载、效率高
*/
public class SingletonDCL {
// 关键字 volatile 防止指令重排序,从而导致 singleton 不为空但没有完成对象的初始化操作
private static volatile SingletonDCL singleton;
private SingletonDCL() {}
public static SingletonDCL getSingleton() {
if (null == singleton) {
synchronized (SingletonDCL.class) {
if (null == singleton) {
// 多线程环境下此处可能出现指令重排序,导致最外层的if判断失效,但此时 singleton 未完成初始化
singleton = new SingletonDCL();
}
}
}
return singleton;
}
}
- 静态内部类(推荐)
/**
* 静态内部类(推荐)
* 特点:线程安全、懒加载、效率高
* 《Java Concurrency in Practice》作者Brian Goetz推荐使用的方式
*/
public class SingletonStaticInner {
private static class SingletonStaticInnerHolder {
private static final SingletonStaticInner singleton = new SingletonStaticInner();
}
private SingletonStaticInner() {}
public static SingletonStaticInner getSingleton() {
return SingletonStaticInnerHolder.singleton;
}
}
- 枚举(推荐)
/**
* 枚举类(推荐,由于枚举的特性,通过反射和序列化/反序列化无法破解单例)
* 特点:线程安全、非懒加载、效率高
* 《Effective Java》作者Joshua Bloch推荐使用的方式
*/
public enum SingletonEnum {
INSTANCE;
}
总结
Spring中bean默认的创建方式就是单例的,工作中大多使用静态内部类的方式创建单例。