设计模式-单例模式
单例模式
定义:用于保证一个类仅有一个实例,并提供别的类访问它的方法。
使用场景:需要控制实例只能有一个、节省资源的时候。
常用的创建单例模式的方法有6种。
- 懒汉式
线程不安全、延迟初始化
public class Singleton {
private Singleton(){}
private static Singleton singleton;
public static Singleton getInstance(){
if(singleton==null){
singleton=new Singleton();
}
return singleton;
}
}
- 懒汉式(加锁)
线程安全、延迟初始化
public class Singleton {
private Singleton(){}
private static Singleton singleton;
public static synchronized Singleton getInstance(){
if(singleton==null){
singleton=new Singleton();
}
return singleton;
}
}
- 饿汉式
线程安全、非延迟初始化
public class Singleton {
private Singleton(){}
private static Singleton singleton=new Singleton();
public static Singleton getInstance(){
return singleton;
}
}
- 双检锁(double-check)
线程安全、延迟初始化
public class Singleton {
private Singleton(){}
private static Singleton singleton;
public static Singleton getInstance(){
if(singleton==null){
synchronized (Singleton.class){
if(singleton==null){
singleton=new Singleton();
}
}
}
return singleton;
}
}
- 静态内部类
线程安全、延迟初始化
public class Singleton {
private Singleton() {
}
private static class SingletonHolder {
private static final Singleton instance = new Singleton();
}
public static final Singleton getInstance() {
return SingletonHolder.instance;
}
}
- 枚举
线程安全、非延迟初始化
这种方式实现简单,并且不仅避免多线程同步问题,而且防止反序列化重新创建新对象。
public enum Singleton {
INSTANCE;
}
单例中的bug;反射创建和反序列化创建。
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Singleton instance1 = Singleton.getInstance();
Constructor<Singleton> declaredConstructor = Singleton.class.getDeclaredConstructor(null);
//跳过权限检查,加载私有构造器
declaredConstructor.setAccessible(true);
Singleton instance2 = declaredConstructor.newInstance();
System.out.println(instance1); //com.mmc.springbootstudy.parteen.singleton.Singleton@5ce65a89
System.out.println(instance2); //com.mmc.springbootstudy.parteen.singleton.Singleton@25f38edc
}
如何避免反射创建呢?
以静态内部类为例,在构造方法中抛异常
如何避免反序列化?
定义一个readResolve()方法,直接返回指定对象
public class Singleton implements Serializable {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){
if(SingletonHolder.INSTANCE!=null){
throw new RuntimeException();
}
}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
//防止反序列化
private Object readResolve(){
return getInstance();
}
}
一般来说我们使用饿汉方式就行了,如果明确要求要延迟初始化,就使用静态内部类的方式。
书山有路勤为径,学海无涯苦作舟