设计模式:单例模式

2023-09-12 20:55:48

什么是单例模式

单例模式是一种创建型设计模式,确保一个类只有一个实例,并提供全局访问点来获取该实例。单例模式的目的是限制一个类只能创建一个对象,以便在整个应用程序中共享该对象的状态和行为。

为什么使用单例模式

在单例模式中,类会提供一个静态方法或静态变量来获取单例实例。这个静态方法会检查是否已经存在实例,如果存在则返回该实例,如果不存在则创建一个新的实例。同时,为了防止通过其他方式创建实例,单例模式的构造函数通常会被设置为私有的,这样外部无法直接实例化该类。

单例模式广泛应用于需要共享资源、控制资源访问以及避免重复创建对象等场景。例如,数据库连接池、日志记录器、配置文件管理器等都可以使用单例模式来实现。

通过单例模式,我们可以确保在整个应用程序中使用相同的实例,避免了资源的浪费和不一致性的问题。

常见的单例写法

1. 懒汉式(Lazy Initialization)

这种写法在第一次使用时才创建实例。示例代码如下:

public class Singleton {
       private static Singleton instance;
       private Singleton() {
           // 私有构造函数,防止外部实例化
       }
       public static synchronized Singleton getInstance() {
           if (instance == null) {
               instance = new Singleton();
           }
           return instance;
       }
   }

这种写法简单直观,但在多线程环境下可能存在线程安全问题,需要使用 synchronized 关键字来解决。

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

这种写法在懒汉式的基础上进行了优化,减少了加锁的开销。示例代码如下:

public class Singleton {
       private volatile static Singleton instance;
       private Singleton() {
           // 私有构造函数,防止外部实例化
       }
       public static Singleton getInstance() {
           if (instance == null) {
               synchronized (Singleton.class) {
                   if (instance == null) {
                       instance = new Singleton();
                   }
               }
           }
           return instance;
       }
   }

使用 volatile 关键字和双重检查的方式,可以在多线程环境下保证线程安全。

3. 饿汉式(Eager Initialization)

这种写法在类加载时就创建实例,不存在线程安全问题。示例代码如下:

public class Singleton {
       private static Singleton instance = new Singleton();
       private Singleton() {
           // 私有构造函数,防止外部实例化
       }
       public static Singleton getInstance() {
           return instance;
       }
   }

这种写法简单直接,但可能会造成资源浪费,因为实例在类加载时就被创建,即使后续并没有被使用到。

4. 枚举实现单例

public class SingletonObj {
    //内部类使用枚举
    private enum SingletonEnum {
        INSTANCE;

        private SingletonObj singletonObj;

        //在枚举类的构造器里初始化singletonObj
        SingletonEnum() {
            singletonObj = new SingletonObj();
        }

        private SingletonObj getSingletonObj() {
            return singletonObj;
        }
    }

    //对外部提供的获取单例的方法
    public static SingletonObj getInstance() {
        //获取单例对象,返回
        return SingletonEnum.INSTANCE.getSingletonObj();
    }
}
  1. enum类的本质其实是一个final修饰的类,因为枚举的性质,INSTANCE 又是由final static 修饰的。所以我们用enum来创建单例,是由JVM来管理这个实例,保证了线程安全。
  2. 防止反序列化产生新的实例:枚举类没有构造方法,也不支持反射机制来创建新的实例,因此可以防止通过反序列化等方式产生新的对象

总结

单例模式比较简单,我们只要确保一个类只有一个实例,并提供全局访问点来获取该实例就行了。在spring源码中是放到一个唯一的且并发安全的Map中,每次使用都是从这个唯一的map中获取对象。

更多推荐

基于Android+OpenCV+CNN+Keras的智能手语数字实时翻译——深度学习算法应用(含Python、ipynb工程源码)+数据集(五)

目录前言总体设计系统整体结构图系统流程图运行环境模块实现1.数据预处理2.数据增强3.模型构建4.模型训练及保存5.模型评估6.模型测试系统测试1.训练准确率2.测试效果3.模型应用1)程序下载运行2)应用使用说明3)测试结果相关其它博客工程源代码下载其它资料下载前言本项目依赖于Keras深度学习模型,旨在对手语进行分

SpringMVC之JSR303和拦截器

目录一、JSR3031.1什么是JSR3031.2为什么要使用JSR3031.3常用注解1.4快速入门1.4.1导入依赖1.4.2配置校验规则1.4.3入门案例二、拦截器2.1什么是拦截器2.1.1定义2.1.2作用领域2.2过滤器2.2.1定义2.2.2作用领域2.3拦截器与过滤器的区别2.4应用场景2.5快速入门2

【软件测试】selenium3

自动化测试的概念自动化测试指软件测试的自动化,在预设状态下运行应用程序或者系统,预设条件包括正常和异常,最后评估运行结果。将人为驱动的测试行为转化为机器执行的过程。自动化测试就相当于将人工测试手段进行转换,让代码去执行。提高测试效率,保障软件质量。自动化测试不能完全代替手工测试。通常是代替那些操作重复性比较高。常见自动

【数据结构】二叉树的节点数,叶子数,第K层节点数,高度,查找x节点,判断是否为完全二叉树等方法

💐🌸🌷🍀🌹🌻🌺🍁🍃🍂🌿🍄🍝🍛🍤📃个人主页:阿然成长日记👈点击可跳转📆个人专栏:🔹数据结构与算法🔹C语言进阶🚩不能则学,不知则问,耻于问人,决无长进🍭🍯🍎🍏🍊🍋🍒🍇🍉🍓🍑🍈🍌🍐🍍文章目录一、二叉数的结构体二、构建二叉树,供后续测试使用三、二叉树销毁四

【 Tkinter界面-练习05】 event和bind

一、说明事件和动作有关;所有的界面都与运动有关,本篇将对事件、事件触发、绑定回调函数等,其实是一系列部件配合的复杂的过程,这些过程牵扯到系统如何设计,线程、消息队列循环等。本篇将详细介绍各种因素的关系。二、事件循环在上一章的末尾,我们解释了如何使用进度条向用户提供有关长时间运行的反馈操作。进度条本身很简单:调用其方法,

【PHP】麻醉临床信息系统

麻醉临床信息系统以服务围术期临床业务工作的开展为核心,为医护人员、业务管理人员、院级领导提供流程化、信息化、自动化、智能化的临床业务综合管理平台。麻醉信息系统处理的数据包含病人的手术信息、麻醉信息、病人手术过程中从监护仪上采集到的数据和病人情况等。一、什么是全麻,什么是“半麻”?麻醉根据对全身的影响分为全身麻醉和部位麻

原生js之var let以及const的区别和作用

ES5:varES6:let、constvar怪异变量首先我们要明确,var是一个块变量也叫作用域变量,如果它放到一个函数中,在函数外调用应该是失败的,在不用vara=1,这样进行定义而变成a=2,时则这个变量就变成了全局变量,如<!DOCTYPEhtml><html><head><metacharset="utf-8

第 4 章 串(串的块链存储实现)

1.背景说明该实现和链表的实现极为相似,只是将链接的内存拆分为具体的大小的块。2.示例代码1).status.h/*DataStructure预定义常量和类型头文件*/#ifndefSTATUS_H#defineSTATUS_H#defineCHECK_NULL(pointer)if(!(pointer)){\prin

Java之File类的详细解析及小练习

2.File类2.1概述java.io.File类是文件和目录路径名的抽象表示,主要用于文件和目录的创建、查找和删除等操作。2.2构造方法publicFile(Stringpathname):通过将给定的路径名字符串转换为抽象路径名来创建新的File实例。publicFile(Stringparent,Stringch

GSMA SGP.01协议学习

GSMASGP.01协议学习1简介1.1概述许多机器对机器设备将不易于达到供应订购的目的。这将需要一个新的解决方案来适应这种特殊情况。要求是在假定采用与今天相同或相似的认证协议的情况下,为具有获得移动网络访问所必需的凭证的“无线”远程配置机器对机器设备定义机制。MNO必须能够响应请求,将订阅(合同)从一个MNOA更改为

薄盒借周杰伦IP卖藏品 车翻在奈雪的茶

在瑞幸联名茅台、喜茶联名FENDI、茶百道联名米哈游后,奈雪的茶搭上了周杰伦。9月14日,在《范特西》专辑发行22周年之际,奈雪的茶推出“范特西音乐宇宙”主题的奶茶与周边。周杰伦系IP加持,奈雪的茶卖爆了,范特西Style的奶茶首日销量达146万杯。然而,车翻得也快,当Jay粉以为奈雪的茶联名了周杰伦时,这个奶茶品牌否

热文推荐