单例模式可不简单

前言

大家好,我是大聪明。设计模式是一套被反复使用的、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了重用代码、让代码更容易被他人理解、保证代码可靠性。

今天我分享一下单例模式的相关知识点,希望对你有所帮助。

单例模式的定义

单例模式是一种常用的创建型设计模式,在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中,使用单例模式的类只存在一个对象实例。

单例模式的特点

  1. 单例类只能有一个实例。
  2. 单例类必须自己自己创建自己的唯一实例。
  3. 单例类必须给所有其他对象提供这一实例

饿汉式

饿汉式的特点是对象实例在初始化的时候就已经创建好了,不管你有没有使用到,具体代码如下:

public class HungrySingleton {
    
    
    // 持有自己类的引用
    private static final HungrySingleton singleton = new HungrySingleton();

    // 私有化构造器
    private HungrySingleton(){}

    // 提供获取实例的静态方法
    public static HungrySingleton getInstance(){
        return singleton;
    }
}

优点:没有线程安全问题

缺点:初始化阶段创建对象,假设实例化对象十分耗时,并且这个实例最后也没有被使用到,岂不是白白浪费资源

懒汉式

懒汉式的特点是在对象被使用的时候才去实例化,比较懒,在用到的时候会检查有没有实例,如果有直接返回,如若没有则新建再返回,具体代码如下:

public class LazySingleton {
    
    
    private static LazySingleton singleton;

    // 私有化构造器
    private LazySingleton(){}

    // 提供获取实例的静态方法
    public static LazySingleton getInstance(){
        // 若对象没有被实例化,则new一下再返回
        if (singleton == null) {
            singleton = new LazySingleton();
        }
        return singleton;
    }
}

优点:只有当对象被使用的时候才会进行实例化

缺点:这种实现最大的问题就是线程不安全,由于没有加锁,在并发情况下可能会实例化出多个对象

双重检测锁

双重检测锁顾名思义就是采用双重判断锁机制安全且在多线程的情况下能保持高性能,相当于懒汉式的一个升级版,具体代码如下:

public class DoubleCheckLockingSingleton {
    
    

    // 注意这里多了一个volatile关键字,面试的时候经常会问这个关键字的作用
    private volatile static DoubleCheckLockingSingleton singleton;

    // 私有化构造器
    private DoubleCheckLockingSingleton(){}

    // 提供获取实例的静态方法
    public static DoubleCheckLockingSingleton getInstance(){
        if (singleton == null) {
            synchronized (DoubleCheckLockingSingleton.class) {
                if (singleton == null) {
                    singleton = new DoubleCheckLockingSingleton();
                }
            }
        }
        return singleton;
    }
}

优点:适合高并发的情况下使用,保证线程安全

缺点:可以通过反射来破坏单例

静态内部类

静态内部类顾名思义就是通过静态的内部类来实现单例模式,这种方式能达到双重检测锁一样的功效,具体代码如下:

public class StaticInnerClassSingleton {
    
    
    // 静态内部类
    private static class SingletonHolder {
        private static final StaticInnerClassSingleton singleton = new StaticInnerClassSingleton();
    }

    // 私有化构造器
    private StaticInnerClassSingleton(){}

    // 提供获取实例的静态方法
    public static StaticInnerClassSingleton getInstance() {
        return SingletonHolder.singleton;
    }
}

优点:线程安全,利用静态内部类的特点实现延迟加载,效率高

缺点:可以通过反射来破坏单例

枚举

在Java中,枚举就是天然的单例,每一个实例只有一个对象,这是Java底层内部机制提供的保证。

public enum EnumSingleton {
    
    
    INSTANCE;
}

优点:JVM保证了枚举是天然的单例,线程安全,自动支持序列化机制,防止反序列化重新创建新的对象,防止多次实例化

总结

单例模式的实现有多种方式,分别从是否线程安全、是否懒加载、是否防止反射构建三个方面进行对比,具体如下:

单例模式实现 是否线程安全 是否懒加载 是否防止反射构建
饿汉式
懒汉式
双重检测锁
静态内部类
枚举

单例模式在面试和工作的过程中经常遇到,你在工作中经常用到哪些设计模式呢?欢迎在下方留言。

—————END—————

​ 喜欢本文的朋友们,那你一定喜欢本文吧!那就点个赞吧!

猜你喜欢

转载自blog.csdn.net/qq_41917138/article/details/126112168