设计模式之单例模式

一、单例模式介绍

单例模式(Singleton Pattern)是一种常用的软件设计模式,它确保一个类仅有一个实例,并提供一个全局访问点来获取该实例。这个模式在多种场景下都非常有用,比如配置文件的读取、数据库连接、线程池等,这些资源通常只需要一个实例来管理,以避免资源浪费或数据不一致。

单例模式的面试题很多,例如:

手写一个单例模式?--主要考察对单例的理解及线程安全环境的理解。

spring是如何实现单例模式的?--主要考察对spring源代码级别的类创建方式理解。

1.单例模式的实现方式

单例模式有多种实现方式,但主要目的是确保类的一个全局访问点和一个实例。以下是几种常见的实现方式(感觉是孔乙己对茴香豆的N种写法):

懒汉式(线程不安全)

懒汉式单例模式在第一次被引用时实例化,但这种方式在多线程环境下可能会创建多个实例。

java 复制代码
public class Singleton {  
    private static Singleton instance;  //instance必须为static,变量属于类全局

    private Singleton() {}  //构造函数必须为private,否则谁都可以new了。

    public static Singleton getInstance() {  //这里多线程进入会有线程安全问题
        if (instance == null) {  
            instance = new Singleton();  
        }  
        return instance;  
    }  
}

懒汉式(线程安全)

通过在getInstance()方法上添加synchronized关键字,可以保证线程安全,但会降低效率。

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

    private Singleton() {}  

    public static synchronized Singleton getInstance() {  
        if (instance == null) {  
            instance = new Singleton();  
        }  
        return instance;  
    }  
}

双重检查锁定(Double-Checked Locking)

双重检查锁定模式既保证了线程安全,又避免了不必要的同步开销。这种方式是懒汉式最佳方案了。

为什么要用volatile看这个文章:【面试题】为什么单例一定要加 volatile?【懒汉模式为什么要用volatile】【volatile的作用】_为啥单例要使用volatile-CSDN博客

java 复制代码
public class Singleton {  
    //volatile是为了保证实例可见性,避免指令重排序,从而避免半初始化问题
    private static volatile Singleton instance;  

    private Singleton() {}  //构造函数必须私有

    public static Singleton getInstance() {  
        if (instance == null) {  //这一层检查是为了提升性能,如果有对象,就直接返回了
            synchronized (Singleton.class) {  //锁加在类对象上,全局唯一
                //new单例之前,先判断,这步很关键,如果删除这个判断,可能会生成多个实例。
                if (instance == null) {  
                    instance = new Singleton();  
                }  
            }  
        }  
        return instance;  
    }  
}

饿汉式

饿汉式单例模式在类加载时就完成了初始化,所以类加载较慢,但获取对象的速度快。

java 复制代码
public class Singleton {  
    private static final Singleton instance = new Singleton();  

    private Singleton() {}  

    public static Singleton getInstance() {  
        return instance;  
    }  
}

静态内部类

静态内部类方式利用了类加载机制来保证初始化实例时只有一个线程,并且实现了懒加载。

java 复制代码
public class Singleton {  
    private Singleton() {}  

    private static class SingletonHolder {  
        private static final Singleton INSTANCE = new Singleton();  
    }  

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

枚举

枚举方式是实现单例模式的最佳方法。它更简洁,自动支持序列化机制,绝对防止多次实例化。

java 复制代码
public enum Singleton {  
    INSTANCE;  

    public void whateverMethod() {  
    }  
}

二、注意事项

  • 单例模式虽然简单,但使用时也需要注意线程安全和性能问题。
  • 在某些场景下,可能需要考虑单例的销毁和资源的释放,尤其是在长时间运行的应用中。
  • 枚举方式是实现单例模式的推荐方式,因为它既简单又安全。但是这个用起来比较别扭,我还是喜欢饿汉式,毕竟自己实现的单例不多,这点启动时间还是可以接受的。

如果觉得对你有用,记得点赞 关注。

相关推荐
沫璃染墨16 小时前
《Linux工程实践篇(一):认识设计模式——从日志系统看策略模式》
linux·c++·安全·设计模式·策略模式
十六宿舍18 小时前
【软件设计模式-第一课:基础知识了解】
设计模式·架构·面向对象·软件架构
geovindu21 小时前
rust: Facade Pattern
开发语言·后端·设计模式·rust·外观模式
怕浪猫1 天前
面试官让我手写一个 Tool Use,我用了 3 种方案
设计模式·面试·程序员
geovindu2 天前
rust: Abstract Factory pattern
开发语言·后端·设计模式·rust·抽象工厂模式
Carl_奕然2 天前
【智能体】Loop 的四种设计模式之:Event-Driven Loop(2026 最新版)
人工智能·驱动开发·python·设计模式
Carl_奕然2 天前
【智能体】Loop 的四种设计模式之:Hill Climbing Loop(2026 最新版)
人工智能·python·设计模式
晚安code3 天前
设计模式入门:吃透 SOLID 原则与迪米特法则,再学 5 个高频模式
后端·设计模式
染指11103 天前
135.Agent-多Agent框架-LangChain多智能体(SubAgents子代理)
数据库·人工智能·设计模式·langchain·agent·agents
路弥行至4 天前
【Head First 设计模式】第 2 章:观察者模式 —— 用现代 C++ 重新解读“交互对象的松耦合
c++·经验分享·笔记·观察者模式·设计模式·入门教程·headfirst