设计模式--单例模式--懒汉饿汉

单例模式

单例模式(Singleton),保证一个类仅有一个实例,并提供一个访问它的全局访问点。

单例模式

通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象。一个最好的办法就是,让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。

结构图

Singleton类,定义一个负责GetInstance操作,允许客户访问它的唯一实例。GetInstance是一个静态方法,主要负责创建自己的唯一实例。

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

    private Singleton() {   // 无参构造私有化,防止外部new对象
    }
    
    // 得到Singleton的实例,唯一的途径
    public static Singleton getInstance() { 
        if (instatnce == null) {
            instatnce = new Singleton();
        }
        return instatnce;
    }
}

客户端

java 复制代码
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();

if (s1 == s2) {
    System.out.println("对象相同");
}

多线程

另外还需要注意一些细节,比如,多线程的程序中,多个线程同时访问Singleton类,调用getInstance()方法时,会可能创建多个实例。我们需要加一些锁。

java 复制代码
public synchronized static Singleton getInstance() {
    if (instatnce == null) {
        instatnce = new Singleton();
    }
    return instatnce;
}

使用synchronized关键字锁住此方法,使得此方法在同一个时间点只有一个线程能进入访问。

这样看起来也没有问题,但是会有一个性能的问题:每次调用此方法的时候都需要锁,但其实我们只需要在创建instance 的时候让一个线程去创建就行。那么再改造一下。

双重锁定

java 复制代码
public class Singleton {

    private volatile static Singleton instatnce;

    private Singleton() {   // 无参构造私有化,防止外部new对象
    }

    // 得到Singleton的实例,唯一的途径
    public static Singleton getInstance() {
        if (instatnce == null) {
            synchronized (Singleton.class){	// 防止多个线程进入创建实例
                if (instatnce == null) {
                    instatnce = new Singleton();
                }
            }
        }
        return instatnce;
    }
}

使用volatile关键字,当synchronized变量被初始化成Singleton时,多个线程能正确处理synchronized变量。

synchronized 代码块儿中,还需要再加一层对instance的判断,因为当多个线程访问此方法时,它们都是通过了第一层instance==null的判断的,里面再加一层判断,防止后进入的线程又一次去创建实例。

静态初始化

在实际应用中,上面的做法都能应付自如。不过为了确保实例唯一,还是会带来很大的性能代价。对于性能要求很高的程序,建议还是采用静态初始化,也就是饿汉模式。

java 复制代码
public class Singleton {

    private static Singleton instatnce = new Singleton();

    private Singleton() {   // 无参构造私有化,防止外部new对象
    }

    // 得到Singleton的实例,唯一的途径
    public static Singleton getInstance() {
        return instatnce;
    }
}

这种静态初始化的方式是在自己被加载时就将自己实例化,所以被形象称之为饿汉式单例类。

要在第一次被引用时,才将自己实例化,则是被称之为懒汉式单例类。

大多数情况都是选择使用饿汉模式单例类,实际按项目需求做出选择。

相关推荐
Doris_202311 小时前
代码格式化 使用oxfmt
设计模式·架构·前端框架
Doris_202311 小时前
说一说ESLint+Prettier生效的原理
前端·设计模式·架构
Pomelooooo12 小时前
把 git commit 这件事,彻底交给 AI ——一个工程化 /git-commit 命令的设计与落地
设计模式
invicinble13 小时前
设计模式(类的拓扑结构)(描述总纲)
设计模式·原型模式
invicinble16 小时前
设计模式(类的拓扑结构)(为什么会产生设计模式,以及什么是设计模式)
linux·服务器·设计模式
PersonalViolet18 小时前
模板方法模式实战:重构Agent工具审批,告别重复代码
设计模式·agent
老码观察18 小时前
设计模式实战解读(五):策略模式——干掉 if-else 的优雅方案
java·设计模式·策略模式
解决问题no解决代码问题19 小时前
设计模式分类介绍
java·开发语言·设计模式
烬羽19 小时前
从 Python List 到 LLM 接口:一条被忽视的 AI 入门捷径
设计模式
IT空门:门主19 小时前
Java 单例模式详解:7 种实现方式 + volatile 原理 + 反射与序列化问题
java·开发语言·单例模式