设计模式之单例模式

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

结构

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

访问类:使用单例类的类

优缺点

优点:

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,则创建一个新的实例

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

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

相关推荐
hqxstudying19 分钟前
Java创建型模式---原型模式
java·开发语言·设计模式·代码规范
Dcs38 分钟前
VSCode等多款主流 IDE 爆出安全漏洞!插件“伪装认证”可执行恶意命令!
java
保持学习ing44 分钟前
day1--项目搭建and内容管理模块
java·数据库·后端·docker·虚拟机
京东云开发者1 小时前
Java的SPI机制详解
java
超级小忍1 小时前
服务端向客户端主动推送数据的几种方法(Spring Boot 环境)
java·spring boot·后端
程序无bug1 小时前
Spring IoC注解式开发无敌详细(细节丰富)
java·后端
小莫分享1 小时前
Java Lombok 入门
java
程序无bug1 小时前
Spring 对于事务上的应用的详细说明
java·后端
食亨技术团队1 小时前
被忽略的 SAAS 生命线:操作日志有多重要
java·后端
苦学编程的谢2 小时前
Maven
java·maven·intellij-idea