单例设计模式

单例设计模式

单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例 ,并提供一个全局访问点来获取这个实例。在软件开发里,有些类的实例只需要存在一个,比如数据库连接池、线程池、日志管理器,factory等,使用单例模式可以避免频繁创建和销毁对象带来的性能开销,同时保证数据的一致性。其实在自己写的而代码中觉得很少使用这种方法,但是在看框架的代码的源码经常看到,那时候觉得,噢,好神奇,然后自己就不会写了。

单例模式的常见应用场景如下:

  • 资源管理类:
  • 数据库连接池:避免频繁创建和销毁连接,减少性能开销,统一管理连接资源。
  • 日志管理器:保证日志信息统一输出和管理,避免多个日志实例冲突。
  • 配置管理类:集中管理全局配置信息,如数据库配置、服务器地址等,方便不同模块访问和修改。
    系统状态管理类:维护全局状态信息,像用户登录状态、系统运行状态等,确保各模块访问和修改状态的一致性。

据说有8种写法,但是我觉得常见的主要是下面的几种:

饿汉式写法:

这个原理是在Java 中,被 static 修饰的成员(变量、代码块)属于类,而非类的某个实例。类加载时,JVM 会对静态成员进行初始化,且这个过程仅执行一次,线程安全是由JVM加载机制负责的,所以不必担心线程安全性的问题。在饿汉式单例模式中,利用 static 修饰单例实例变量或者将实例创建代码放在静态代码块里,能确保单例实例在类加载时就被创建。

这个据说是最实用的方法,其实我觉得也是。

java 复制代码
public class Singleton {
    // 在类加载时就创建实例
    private static final Singleton INSTANCE = new Singleton();

    // 私有构造函数,防止外部实例化,无法实现私有化
    private Singleton() {}

    // 全局访问点
    public static Singleton getInstance() {
        return INSTANCE;
    }
}

优点:实现简单,线程安全。

缺点:如果单例实例在整个应用程序中不一定会被使用,类加载时就创建实例会造成资源浪费。
*

懒汉式写法(非线程安全)

为了解决在不使用的时候不进行创建实例,懒汉式在第一次调用 getInstance() 方法时才创建单例实例,但是这就造成了在多线程的环境下出现了可能创建多个实例。

java 复制代码
public class Singleton {
    private static Singleton instance;

    private Singleton() {}

    // 全局访问点
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

优点:延迟加载,只有在需要时才创建实例,节省资源。

缺点:线程不安全,在多线程环境下可能会创建多个实例。
*

线程安全的懒汉式(Synchronized)

为了进一步解决懒汉式的线程安全问题,可以在 getInstance() 方法上添加 synchronized 关键字。

java 复制代码
public class Singleton {
    private static Singleton instance;

    private Singleton() {}

    // 全局访问点,添加 synchronized 关键字保证线程安全
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

虽然保证了线程的安全性,带来的缺点是运行的效率下降。
*

双重检查锁定

双重检查锁定是一种更高效的线程安全懒汉式实现方式。

java 复制代码
public class Singleton {
    // 使用 volatile 关键字保证可见性
    private static volatile Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {//如果只保留这个检查还是不能保证线程安全
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

实现变得更加复杂,涉及指令重排序的问题,这个不懂!
*

静态内部类的实现单例模式
java 复制代码
public class Singleton {
    private Singleton() {}

    //静态内部类在外部类被加载时并不会被加载,只有当调用获取单例实例的方法时,才会触发静态内部类的加载和初始化,而类的初始化过程由 JVM 保证线程安全,因此可以确保单例实例的唯一性。
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }

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

延迟加载机制:

静态内部类实现单例模式还具备延迟加载的特性。外部类加载时,静态内部类不会被加载,只有在调用获取单例实例的方法时,静态内部类才会被加载并初始化静态变量,从而创建单例实例。这样可以避免在应用启动时就创建单例实例,节省系统资源。
*

枚举类实现
java 复制代码
// 定义一个枚举类型作为单例类
public enum EnumSingleton {
    // 单例实例
    INSTANCE;

    // 可以添加其他方法和属性
    public void doSomething() {
        System.out.println("枚举单例执行操作");
    }
}
相关推荐
孫治AllenSun4 分钟前
【Maven】手动安装依赖到本地仓库
java·maven
MacroZheng9 分钟前
斩获10k star!这款开源的项目管理工具,能让你的开发效率翻倍!
java·spring boot·后端
Code哈哈笑9 分钟前
【Spring Boot基础】MyBatis的基础操作:日志、增删查改、列名和属性名匹配 -- 注解实现
java·spring boot·后端·spring·mybatis
啊阿狸不会拉杆10 分钟前
数据结构-数组与广义表
java·c语言·数据结构·c++·python·算法
爱的叹息13 分钟前
【java实现+4种变体完整例子】排序算法中【冒泡排序】的详细解析,包含基础实现、常见变体的完整代码示例,以及各变体的对比表格
java·算法·排序算法
Minyy1131 分钟前
SSM(SpringMVC+spring+mybatis)整合的步骤以及相关依赖
java·后端·spring·servlet·maven·intellij-idea·mybatis
牛奶咖啡1336 分钟前
学习设计模式《四》——单例模式
单例模式·设计模式·饿汉式单例·懒汉式单例·线程安全的单例·可控制实例数量的单例·何时使用单例模式
人工智能那些事儿41 分钟前
神经网络:从基础到应用,开启智能时代的大门
java·人工智能·python·深度学习·神经网络·算法·机器学习
MiniFlyZt1 小时前
分布式数据库TiDB:架构、核心特性与生产实践(分库分表)
java·数据库·分布式·spring cloud·微服务·tidb
zzx_nihao1 小时前
Java29:Spring MVC
java·spring·mvc