设计模式-单例模式

单例模式

定义:用于保证一个类仅有一个实例,并提供别的类访问它的方法。

使用场景:需要控制实例只能有一个、节省资源的时候。

常用的创建单例模式的方法有6种。

  1. 懒汉式

线程不安全、延迟初始化

public class Singleton {

    private Singleton(){}
    
    private static Singleton singleton;
    
    public static Singleton getInstance(){
        if(singleton==null){
            singleton=new Singleton();
        }
        return singleton;
    }
}
  1. 懒汉式(加锁)

线程安全、延迟初始化

public class Singleton {

    private Singleton(){}

    private static Singleton singleton;

    public static synchronized Singleton getInstance(){
        if(singleton==null){
            singleton=new Singleton();
        }
        return singleton;
    }
}
  1. 饿汉式

线程安全、非延迟初始化

public class Singleton {

    private Singleton(){}

    private static Singleton singleton=new Singleton();

    public static  Singleton getInstance(){
        return singleton;
    }
}
  1. 双检锁(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;
    }
}
  1. 静态内部类

线程安全、延迟初始化

public class Singleton {


    private Singleton() {
    }

    private static class SingletonHolder {
        private static final Singleton instance = new Singleton();
    }

    public static final Singleton getInstance() {
        return SingletonHolder.instance;
    }
}
  1. 枚举

线程安全、非延迟初始化

这种方式实现简单,并且不仅避免多线程同步问题,而且防止反序列化重新创建新对象。

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();
    }
}

一般来说我们使用饿汉方式就行了,如果明确要求要延迟初始化,就使用静态内部类的方式。

返回目录

书山有路勤为径,学海无涯苦作舟
原文地址:https://www.cnblogs.com/javammc/p/14938637.html