设计模式之单例模式

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

结构

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

访问类:使用单例类的类

优缺点

优点:

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

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

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

相关推荐
虾条_花吹雪几秒前
Chat Model API
java
双力臂4046 分钟前
MyBatis动态SQL进阶:复杂查询与性能优化实战
java·sql·性能优化·mybatis
六毛的毛37 分钟前
Springboot开发常见注解一览
java·spring boot·后端
程序漫游人1 小时前
centos8.5安装jdk21详细安装教程
java·linux
超级码.里奥.农1 小时前
零基础 “入坑” Java--- 七、数组(二)
java·开发语言
hqxstudying2 小时前
Java创建型模式---单例模式
java·数据结构·设计模式·代码规范
挺菜的2 小时前
【算法刷题记录(简单题)002】字符串字符匹配(java代码实现)
java·开发语言·算法
A__tao2 小时前
一键将 SQL 转为 Java 实体类,全面支持 MySQL / PostgreSQL / Oracle!
java·sql·mysql
一只叫煤球的猫2 小时前
真实事故复盘:Redis分布式锁居然失效了?公司十年老程序员踩的坑
java·redis·后端
猴哥源码2 小时前
基于Java+SpringBoot的农事管理系统
java·spring boot