设计模式:1.单例模式

什么是单例模式

单例模式目的是保证在程序运行期间一个类只有一个实例,并提供一个全局访问点,无论什么情况下,只会生成一个实例,免去繁琐的创建销毁对象的过程。

如何设计单例

如何设计单例模式其实很简单,只需要考虑一个问题,实例是否可以保证是全局唯一,只要满足这个条件,这个单例设计的肯定就合格了。

其中懒汉模式,饿汉模式,双重检查方式实现,静态内部类的实现方式都可以概括为以下两步:

构造函数私有化,保证在外部无法new对象
提供一个static方法获取当前实例(不同方案,实现不同)
当然枚举的实现方式最简单,也最安全的,所以推荐使用枚举实现,其次推荐使用静态内部类方式实现。

饿汉模式
不是延迟加载,加载类的时候直接初始化

/**
 * @auther: linan
 * @date: 2020/5/25 16:26
 * @description:
 */
public class Singleton {

    private static Singleton singleton = new Singleton();

    private Singleton() {
    }

    public static Singleton getInstance(){
        return singleton;
    }
}

优点:线程安全,代码简单。

缺点:不是延迟加载,如果你用不到这个类,它也会实例化,还有一个问题就是如果这个实例依赖外部一些配置文件,参数什么的,在实例化之前就要获取到,否则就实例化异常

懒汉模式
延迟加载,首次需要使用的时候在实例化,需要考虑线程安全

线程不安全的实现方式

public class Singleton {

    private static Singleton singleton;

    private Singleton() {
    }

    public static Singleton getInstance(){
        if(null == singleton){
            singleton = new Singleton();
        }
        return singleton;
    }
}

双重检查(DCL:Double Check Lock)
线程安全的实现方式:

public class Singleton {

    private static volatile Singleton singleton;

    private Singleton() {
    }

    public static Singleton getInstance(){
        if(null == singleton){
            synchronized (Singleton.class){
                if(null == singleton){
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}

为什么使用volatile修饰singleton变量?

说的volatile,首先肯定回答volatile的可见性
防止重排序优化,如果不用volatile修饰,多线程的情况下,可能会出现线程A进入synchronized代码块,执行new Singleton();,首先给singleton分配内存,但是还没有初始化变量,这时候线程B进入getInstance方法,进行第一个判断,此时singleton已经不为空,直接返回singleton,然后肯定报错。使用volatile修饰之后禁止jvm重排序优化,所以就不会出现上面的问题

静态内部类实现
使用静态内部类实现也是延迟加载,利用静态内部类去实现线程安全,只有在第一次调用getInstance方法的时候才会去加载SingletonHolder,初始化SINGLETON

public class Singleton {

    private Singleton() {
    }

    public static Singleton getInstance(){
        return SingletonHolder.SINGLETON;
    }

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

枚举实现
枚举实现代码更简洁,线程安全,并且保证枚举不会被反序列化,反射和克隆

/**
 * @auther:linan
 * @date: 2020/5/25 16:30
 * @description:
 */
public enum Singleton {
    
    SINGLETON;

    /**
     * 提供的方法
     */
    public void method(){
        System.out.println("枚举实现");
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章