当前位置:   article > 正文

设计模式(一):单例模式详解以及几种实现方式及其优缺点_单例模式知道吗,会引起什么问题?

单例模式知道吗,会引起什么问题?


579a429daf314744b995f37351b46548

前言

软件开发中,单例模式是一种常见的设计模式,用于确保一个类只有一个实例,并提供全局访问点。

单例模式可以在多线程环境下保持数据的一致性,同时也可以节省系统资源。

本文将详细介绍单例模式的概念、几种实现方式以及它们的优缺点,帮助读者更好地理解和应用单例模式。


概念

单例:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

单例模式是一种常用的软件设计模式之一,其目的是保证整个应用中只存在类的唯一个实例。

比如我们在系统启动时,需要加载一些公共的配置信息,对整个应用程序的整个生命周期中都可见且唯一,这时需要设计成单例模式。如:spring容器,session工厂,缓存,数据库连接池等等。

如图

image-20201010005310340


特点

1)单例模式只能有一个实例。

2)单例类必须创建自己的唯一实例。

3)单例类必须向其他对象提供这一实例。


如何保证实例的唯一

1)保证实例化一次

2)由类本身进行实例化

3)防止外部初始化

4)对外提供获取实例的方法

5)线程安全


几种单例模式以及优缺点

image-20231127153430679

懒汉模式

在用的时候才加载,延迟加载

线程不安全示例

public class SlackerSingletonDemo {
    private  static SlackerSingletonDemo instance;
    private SlackerSingletonDemo(){

    }
    public static SlackerSingletonDemo getInstance() {
        if (instance == null) {
            instance = new SlackerSingletonDemo();
        }
        return instance;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
优点

在获取实例的方法中,进行实例的初始化,节省系统资源

缺点

1.如果获取实例时,初始化工作较多,加载速度会变慢,影响系统系能

2.每次获取实例都要进行非空检查,系统开销大

3.非线程安全,当多个线程同时访问getInstance()时,可能会产生多个实例

如果需要线程安全 在getInstance 加synchronized

线程安全示例

public class SlackerSingletonDemo {
    private  static SlackerSingletonDemo instance;
    private SlackerSingletonDemo(){

}
public static synchronized SlackerSingletonDemo getInstance() {
    if (instance == null) {
        instance = new SlackerSingletonDemo();
    }
    return instance;
}

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

这种的缺点就是synchronized锁占用的资源浪费

饿汉模式

在定义类的静态私有变量同时进行实例化

public class HungrySingletonDemo {
    private static HungrySingletonDemo instance = new HungrySingletonDemo();
    private HungrySingletonDemo(){

    }

    public static HungrySingletonDemo getInstance() {
        return instance;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

1.声明静态私有类变量,且立即实例化,保证实例化一次

2.私有构造,防止外部实例化(通过反射是可以实例化的,不考虑此种情况)

3提供public的getInstance()方法供外部获取单例实例

好处

1.线程安全

2.获取实例速度快

缺点

类加载即初始化实例,内存浪费

DCL模式

Double Check Lock,双重锁判断机制

public class DCLSingletonDemo {
    private volatile static DCLSingletonDemo instance;
    private DCLSingletonDemo(){

    }

    public static DCLSingletonDemo getInstance() {
        if (instance == null) {
            synchronized (DCLSingletonDemo.class){
                if (instance == null) {
                    instance = new DCLSingletonDemo();
                }
            }
        }
        return instance;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
优点

线程安全,进行双重检查,保证只在实例未初始化前进行同步,效率高

缺点

还是实例非空判断,耗费一定资源

静态内部类实现模式

线程安全,调用效率高,可以延时加载

public class StaticSingletonDemo {
    private static class StaticSingletonDemoInstance{
        private static final StaticSingletonDemo instance=new StaticSingletonDemo();
    }

    private StaticSingletonDemo(){

    }
    public static StaticSingletonDemo getInstance(){
        return StaticSingletonDemoInstance.instance;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
优点

既避免了同步带来的性能损耗,又能够延迟加载

枚举模式
public enum  EnumSingletonDemo {
    //枚举元素本身就是单例
    INSTANCE;
    public void init() {
        System.out.println("资源初始化。。。");

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

优点:天然线程安全,可防止反射生成实例。

如何选用

-单例对象 占用资源少,不需要延时加载,枚举 好于 饿汉

-单例对象 占用资源多,需要延时加载,静态内部类 好于 懒汉


单例模式的优缺点

优点

1.该类只存在一个实例,节省系统资源

2.对于需要频繁创建销毁的对象,使用单例模式可以提高系统性能。

缺点

不能外部实例化(new),调用人员不清楚调用哪个方法获取实例时会感到迷惑,尤其当看不到源代码时。


总结

单例模式是一种常见的设计模式,用于确保一个类只有一个实例,并提供全局访问点。

本文介绍了几种常见的单例模式实现方式:饿汉式、懒汉式、双重检查锁、静态内部类和枚举类。

每种实现方式都有其优缺点,具体选择哪种方式取决于实际需求和场景。通过合理应用单例模式,我们可以提高系统的性能和资源利用率。


写在最后

感谢您的支持和鼓励!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家自动化/article/detail/525459
推荐阅读
相关标签