设计模式学习笔记-单例模式的几种实现方式

单例定义

单例模式(Singleton Design Pattern),一个类只允许创建一个对象(或者实例),那这个类就时一个单例类,这种设计模式就时单例模式

单例的几种实现

1、饿汉式

饿汉式的实现方式是在类加载的时候,instance静态实例已经创建并初始化好了,这种方式是线程安全的,但是并不支持延迟加载,也就是不能在用到的时候再去创建实例

public class SingletonTest {
    private static SingletonTest instance = new SingletonTest();
    private SingletonTest (){}
    public static SingletonTest getInstance() {
        return instance;
    }
}

这种方式因为不支持延迟加载,如果实例占用资源多或者初始化耗时时间长的话,我们就可以把这个耗时长的初始化过程提前到程序启动的时候完成,这样可以避免我们在真正调用这个实例的时候再去执行初始化,这会影响到系统的性能,同时,如果占用的资源过多,也会再程序初始化的时候出发报错,比如OOM,我们可以去立即修复,否则当程序跑起来了,突然因为初始化这个实例需要大量的资源,导致系统崩溃,那就凉凉了。这就涉及到是以时间换空间,还是以空间换时间的问题思考了

2、懒汉式

懒汉式相对于饿汉式的优势是支持延迟加载

public class SingletonTest {
    private static SingletonTest instance;
    private SingletonTest (){}
    public static synchronized SingletonTest getInstance() {
        if(instance == null){
            instance = new SingletonTest();
        }
        return instance;
    }
}

懒汉式中,给getInstance()加了把锁,这就导致这个函数如果在被频繁调用的时候,频繁的加锁、释放锁以及并发度的问题会导致性能瓶颈

3、双重检测

这种方式相等于解决了饿汉式和懒汉式的缺点,由于饿汉式不支持延迟加载,而懒汉式有性能问题,不支持高并发,所以就有了双重检测的实现方式;这种实现方式,只要instance被创建之后,即便再调用getInstance()函数也不会再进入加锁逻辑中了

public class SingletonTest {
    private static volatile SingletonTest instance;
    private SingletonTest (){}
    public static SingletonTest getInstance() {
        if(instance == null){
            synchronized (SingletonTest.class){ // 此处为类级别的锁
                if(instance == null){
                    instance = new SingletonTest();
                }
            }
        }
        return instance;
    }
}

双重检测的原理是:线程A,线程B,先后执行get方法,进行对象为空的判断,A线程争抢到锁资源,进行实例化对象,并进行赋值,逻辑处理,当该线程执行完实例化对象后,其他线程抢到锁资源,如果不进行一次对象为空判断,那就会再次创建一个该类的实例化对象。
这里instance 成员变量上加了volatile关键字,可以禁止指令重排序,但是我看到有的大佬说可以不加这个关键字,因为高版本的java已经在jdk内部实现中解决了这个问题,关于这个问题,可以找个时间研究一下

4、静态内部类

这种方式比双重校验要简单一些,就是利用静态内部类,类似于饿汉式,但是又做到了延迟加载

public class SingletonTest {
    private static volatile SingletonTest instance;
    private SingletonTest (){}

    private static class SingletonHolder{
        private static final SingletonTest instance = new SingletonTest();
    }
    
    public static SingletonTest getInstance(){
        return SingletonHolder.instance;
    }
}

SingletonHolder是一个静态内部类,当调用getInstance()方法时,才会被加载,这个时候才会创建instance。instance的唯一性、创建过程的线程安全都由JVM来保证。所以,这种实现方式即保证了线程安全,又能做到延迟加载

5、枚举

这种方式通过java枚举类型本身的特性,保证了实例创建的线程安全和唯一性

public enum Singleton {
    INSTANCE;
}

你可能感兴趣的:(设计模式)