单例模式(Singleton Pattern)

单例模式(Singleton Pattern)

定义

是指确保一个类在任何情况下都绝对只有一个实例,并提供一个全局访问点。

隐藏起所有的构造方法。

属于创建型模式。


适用场景

确保任何情况下都绝对只有一个实例。
比如数据库连接池、配置文件读取、缓存等。


标准示例

在这里插入图片描述

1. 饿汉式单例

在单例类首次加载时,就创建实例。

  • 优点:执行效率高,性能高,没有锁
  • 缺点:某些情况下,可能会有内存浪费(系统中单例类很多的时候,无论是否使用,加载时都会初始化到内存)
public class HungrySingleton {
    //静态成员变量
    private static final HungrySingleton INSTANCE;
    //代码块对成员变量赋初始值
    static {
        INSTANCE = new HungrySingleton();
    }

    //私有的构造函数
    private HungrySingleton(){}

    //全局访问方法
    public static HungrySingleton getInstance(){
        return INSTANCE;
    }
}

2. 懒汉式单例

被外部类调用时才会创建实例。

  • 优点:节省了内存
  • 缺点:线程不安全问题
public class LazySingleton {
    private static LazySingleton instance;

    private LazySingleton(){}

    public static LazySingleton getInstance(){
        if(instance == null){
            // 位置A
            instance = new LazySingleton();
            // 位置B
        }
        // 位置C
        return instance;
    }
}

上述代码的线程不安全体现在两种情况:

两个线程输出实例相同,实际上是后者覆盖了前者:
有两个线程,都执行到了位置B,这时后者会覆盖掉前者,当线程继续到位置C时,它们输出的确是同一个实例——把前者覆盖掉的那个实例。

两个线程同时进入非空判断条件中,然后按顺序返回,输出两个不同实例:
有两个线程,一个执行到了位置A,另一个执行到了位置B,然后位置B的线程执行到位置C,输出它的实例;位置A的也随后执行到位置B,创建了新的实例覆盖原有实例,然后执行到位置C输出该新实例。两次输出的是不同的实例

解决懒汉式单例线程安全问题的方法一:加锁

public class LazySingleton {
    private static LazySingleton instance;
    
    private LazySingleton(){
    }

	//加锁解决线程安全问题
    public synchronized static LazySingleton getInstance(){
        if(instance == null){
            instance = new LazySingleton();
        }
        return instance;
    }
}

但是,这种方式会有副作用,所有的获取实例的调用,都会受到synchronized的性能影响。

解决懒汉式单例线程安全问题的方法二:双重检查

public class DoubleCheckLazySingleton {
	//加 volatile 是为了解决指令重排序的问题,保证instanc变量先创建
    private volatile static DoubleCheckLazySingleton instance;

    private DoubleCheckLazySingleton(){
    }

    public static DoubleCheckLazySingleton getInstance(){
        //第一次检查,目的是要判断是否要加锁
        if(instance == null){
            synchronized (DoubleCheckLazySingleton.class){
                //第二次检查,目的是判断是否要创建实例
                if(instance == null) {
                    instance = new DoubleCheckLazySingleton();
                }
            }
        }
        return instance;
    }
}

上述代码可以解决问题,只是可读性不够高。

解决懒汉式单例线程安全问题的方法三:静态内部类
利用原理:内部类只有在调用时才会被加载。

public class StaticInnerClassLazySingleton {
    private StaticInnerClassLazySingleton(){}

    public static StaticInnerClassLazySingleton getInstance(){
        return LazyInnerClass.INSTANCE;
    }

    private static class LazyInnerClass{
        private static final StaticInnerClassLazySingleton INSTANCE = new StaticInnerClassLazySingleton();
    }
}

3. 注册式单例

将每一个实例都缓存到统一的容器中,使用唯一标识获取实例

public class ContainerSingleton {
    private ContainerSingleton(){}

    private static ContainerSingleton instance;

    private static Map<String,Object> ioc = new ConcurrentHashMap<String, Object>();

    public static Object getInstance(String className){
        Object instance = null;
        if(!ioc.containsKey(className)){
            try {
                instance = Class.forName(className).newInstance();
                ioc.put(className,instance);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return  instance;
        }else{
            return ioc.get(className);
        }
    }
}

以上就是 单例模式 的全部内容,感谢阅读。

相关推荐

  1. .NET 设计模式模式SingletonPattern

    2024-07-11 13:16:03       34 阅读
  2. 模式模板

    2024-07-11 13:16:03       39 阅读
  3. 模式【C#】

    2024-07-11 13:16:03       50 阅读
  4. python模式

    2024-07-11 13:16:03       56 阅读
  5. 模式详解

    2024-07-11 13:16:03       56 阅读
  6. 模式学习

    2024-07-11 13:16:03       43 阅读
  7. 模式(C++)

    2024-07-11 13:16:03       45 阅读
  8. 设计模式

    2024-07-11 13:16:03       59 阅读
  9. 【C++ 模式

    2024-07-11 13:16:03       61 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-11 13:16:03       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-11 13:16:03       72 阅读
  3. 在Django里面运行非项目文件

    2024-07-11 13:16:03       58 阅读
  4. Python语言-面向对象

    2024-07-11 13:16:03       69 阅读

热门阅读

  1. 达梦数据库系列—23. DSC集群搭建

    2024-07-11 13:16:03       17 阅读
  2. RabbitMQ 迁移

    2024-07-11 13:16:03       21 阅读
  3. 【编程范式】理解响应式编程(reactive programming)

    2024-07-11 13:16:03       26 阅读
  4. Python 循环语句

    2024-07-11 13:16:03       21 阅读
  5. 【EasyExcel】动态替换表头内容并应用样式

    2024-07-11 13:16:03       21 阅读
  6. IPython的使用技巧整理

    2024-07-11 13:16:03       23 阅读
  7. uniapp踩坑小伎俩记录

    2024-07-11 13:16:03       22 阅读