设计模式之单例模式

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

结构

单例类:只能创建一个实例的类

访问类:使用单例类的类

优缺点

优点:

1、在内存里只有一个实例,减少了内存的开销

2、避免对资源的多重占用

缺点:

没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化

特点

1.单例类只能有一个实例

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

3.单例类必须给所有其他对象提供这一实例

使用场景

1.有频繁的实例化后又销毁的情况,适合考虑使用单例模式,如记录日志的log对象

2.创建对象需要消耗过多的系统资源,但又经常用到的资源,如数据库连接

创建模式

饿汉式

在该类初始化的时候就创建实例对象,线程是安全的

java 复制代码
public class Singleton {  
    // 在类加载时就完成了初始化,所以类加载较慢,但获取对象的速度快  
    private static Singleton instance = new Singleton();  
  
    // 私有化构造函数,防止外部创建对象  
    private Singleton(){}  
  
    // 提供一个全局访问点  
    public static Singleton getInstance(){  
        return instance;  
    }  
}

饿汉式单例模式的优点是线程安全且效率高。由于实例在类加载时就创建了,所以获取对象的速度快。此外,由于构造函数是私有的,外部无法创建实例,因此可以保证只有一个实例

缺点:

饿汉式单例模式的缺点是可能会造成内存空间的浪费。如果该实例需要消耗大量的内存,且在程序的生命周期内可能不会使用到这个实例,那么就会造成内存空间的浪费

懒汉式

首次使用单例实例的时候创建,之后使用时再判断单例实例是否已创建,如果没有则创建实例

java 复制代码
public class Singleton {  
    // 私有静态变量,用于保存单例对象  
    private static Singleton instance;  
  
    // 私有化构造函数,防止外部创建对象  
    private Singleton(){}  
  
    // 在第一次使用时,通过静态代码块创建实例  
    private static void initializeInstance() {  
        instance = new Singleton();  
    }  
  
    // 提供一个全局访问点  
    public static Singleton getInstance(){  
        if (instance == null) {  
            initializeInstance();  
        }  
        return instance;  
    }  
}

instance变量在第一次调用getInstance()方法时才创建,因此线程是不安全的。为了实现线程安全,可以使用双重检查锁定、静态初始化块、枚举方式

优点:

只有在需要使用实例时才创建。这可以节省内存空间,特别是对于那些在程序生命周期中不一定需要的实例

双重检查锁定

java 复制代码
public class Singleton {  
    // 使用volatile关键字,确保该变量在多线程环境下保持可见性  
    private volatile static Singleton instance;  
  
    // 私有化构造函数,防止外部创建对象  
    private Singleton(){}  
  
    // 在第一次使用时,通过静态代码块创建实例  
    private static void initializeInstance() {  
        instance = new Singleton();  
    }  
  
    // 提供一个全局访问点  
    public static Singleton getInstance(){  
        // 第一次检查,如果instance不为null,说明实例已经被初始化,直接返回实例即可  
        if (instance == null) {  
            synchronized (Singleton.class) {  
                // 第二次检查,如果instance为null,说明实例还没有被初始化,需要进入同步块进行初始化  
                if (instance == null) {  
                    instance = new Singleton();  
                }  
            }  
        }  
        return instance;  
    }  
}

instance变量使用volatile关键字修饰,以确保在多线程环境下保持可见性。双重检查锁定通过两次检查instance变量的值是否为null来实现线程安全

静态初始化块

java 复制代码
public class Singleton {  
    // 私有静态变量,用于保存单例对象  
    private static Singleton instance;  
  
    // 私有化构造函数,防止外部创建对象  
    private Singleton(){}  
  
    // 使用静态初始化块来创建实例  
    static {  
        instance = new Singleton();  
    }  
  
    // 提供一个全局访问点  
    public static Singleton getInstance(){  
        return instance;  
    }  
}

instance变量在类加载时创建实例,因此它是线程安全的。

优点:避免了在第一次调用getInstance()方法时进行同步的开销;线程安全的,可以确保只创建一个实例

缺点:会造成类加载的开销

枚举方式

枚举类实现单例模式是极力推荐的单例实现模式,因为枚举是线程安全的,并且只会装载一次,枚举类是所有单例类实现中唯一不会被破坏的单例模式

java 复制代码
public enum Singleton {  
    INSTANCE;  
  
    // 单例对象  
    private Singleton instance;  
  
    // 私有方法,用于创建实例  
    private void createInstance() {  
        instance = new Singleton();  
    }  
  
    // 公共方法,用于获取实例  
    public Singleton getInstance() {  
        if (instance == null) {  
            synchronized (Singleton.class) {  
                if (instance == null) {  
                    createInstance();  
                }  
            }  
        }  
        return instance;  
    }  
}

instance变量在枚举类型被加载时创建实例,因此它是线程安全的。枚举类型在Java中是线程安全的,并且只有一个实例。getInstance()方法用于获取实例,它首先检查instance变量是否为null,如果是null,则进入同步块,再次检查instance变量是否为null,如果是null,则创建一个新的实例

优点:具有更高的性能和更少的内存占用;使用枚举实现的单例模式更加简单和安全

缺点:只能创建单一的实例,无法实现多个实例的创建和管理

相关推荐
ldj202015 分钟前
SpringBoot为什么使用new RuntimeException() 来获取调用栈?
java·spring boot·后端
超龄超能程序猿16 分钟前
Spring 应用中 Swagger 2.0 迁移 OpenAPI 3.0 详解:配置、注解与实践
java·spring boot·后端·spring·spring cloud
风象南28 分钟前
SpringBoot配置属性热更新的轻量级实现
java·spring boot·后端
洛阳泰山29 分钟前
Spring Boot 整合 Nacos 实战教程:服务注册发现与配置中心详解
java·spring boot·后端·nacos
Y40900129 分钟前
C语言转Java语言,相同与相异之处
java·c语言·开发语言·笔记
YuTaoShao30 分钟前
【LeetCode 热题 100】994. 腐烂的橘子——BFS
java·linux·算法·leetcode·宽度优先
布朗克16830 分钟前
java常见的jvm内存分析工具
java·jvm·数据库
都叫我大帅哥2 小时前
深入浅出 Resilience4j:Java 微服务的“免疫系统”实战指南
java·spring cloud
Cao_Shixin攻城狮4 小时前
Flutter运行Android项目时显示java版本不兼容(Unsupported class file major version 65)的处理
android·java·flutter
Dcs6 小时前
还在用 Arrays.hashCode?Java 自己也能写出更快的版本!
java