常见单例模式详解

news2025/1/16 21:08:49

单例模式是23种设计模式中应用最广的模式之一,其定义:确保某一个类只有一个实例,而且自行实实例化并向整个系统通过这个实例。其类图如下:

image.gif

通俗来说,单例模式就是用于创建那些在软件系统中独一无二的对象。在一个软件系统中,往往无需创建多个实例。举个大家熟悉的例子— Windows任务管理器。有兴趣的可以试下,按住Ctrl + Alt + Del然后在弹出的界面中选择任务管理器或者在菜单栏右键弹出菜单上多次点击启动任务管理器,你会发现,无论启动多少次,Windows系统只会弹出一个任务管理器窗口,这是日常生活最常见的单例模式应用之一。采用单例模式可以避免产生多个对象而导致消耗过多的资源问题,比如要进行IO访问操作或便利查询数据库等,这时单例模式就是一个较好的解决方案。

实现方式

1、构造方法属性改为private;
2、通过一个静态方法返回一个全局单例类对象;
3、在系统中无论何种情况下或在子线程中,单例对象都只有一个,不会重复创建单例对象。

而根据其实现方式细节不同,又可分为以下几种:

饿汉式

public class Singletion {

    private Singletion() {

    }
    
    private static final Singletion mInstance = new Singletion();

    public static Singletion getInstance() {
        return mInstance;
    }
}

此方式在声明静态对象时就初始化(在类装载(ClassLoader)时就构建,也可以说预先加载),通过static关键字修饰静态变量,将其存储在内存中,确保只有一份数据。
而final关键字,使得只初始化一次,所以mInstance实例只有一个。

此方式线程安全,由于在类加载的同时就已经创建好一个静态对象,所以调用时耗时短、速度快(优点)。
但也有可能getInstance()永远不会执行,但执行该类的其他静态方法或者加载了该类(class.forName),那么这个类仍然会初始化,可能会浪费资源(缺点)。

懒汉式

public class Singletion {
    
    private  Singletion() {}

    private static Singletion mInstance;

    public static synchronized Singletion getInstance() {
        if (mInstance == null) {
            mInstance = new Singletion();
        }
        return mInstance;
    }
}

该类在调用getInstance的时候(使用)才初始化,但这里加了synchronized关键字,就变成了一个同步方法。相较于饿汉式的“空间换时间”特点,懒汉式是“时间换空间”。
由于在使用时才会进行实例化,可以说节省了系统资源(优点);
但每次调用getInstance都会同步一次,浪费系统资源(缺点)。

双重检测加锁方式

public class Singletion {

    private Singletion() {}

    private volatile static Singletion mInstance;
    
    public static Singletion getInstance() {
        if (mInstance == null) {
            synchronized (Singletion.class) {                
                if (mInstance == null) {
                    mInstance = new Singletion ();                
                }
            }
        }
        return mInstance;
    }
}

这里使用 volatile 可以禁止 JVM 的指令重排,保证在多线程环境下也能正常运行(指令重排单线程环境不会出问题,但是多线程场景下会导致一个线程获得还没有初始化的实例),举个例子:

...
private static Singletion mInstance;
private Singletion() {}
public static Singletion getInstance() {...}
...

由于JVM是可以乱序执行方法的,上面三句方法在执行过程可能出现下面场景:
如果A线程执行getInstance(),还没执行构造方法Singletion(),此时B线程调用getInstance(),因为A线程已经执行了getInstance(),所以mInstance不为空就直接获取到实例,由于B线程直接获取,而真实情况是A线程构造方法还未执行,所以mInstance就为空了
虽然概率较小,但也有可能发生,故JDK自1.6开始加入volatile关键字,虽然必不可免的会消耗一些性能。

此方式资源利用率高,不执行getInstance()就不会被实例,可以执行该类的其他静态方法(优点);
但同时也存在第一次加载时较慢多线程使用会有不必要的同步开销的问题(缺点)。

静态内部类方式

class Singletion {
    private Singletion() {
    }

    private static class SingletonLoader {
        static Singletion mInstance = new Singletion();
    }

    public static Singletion getInstance() {
        return SingletonLoader.mInstance;
    }
}

此类在调用getInstance的时候才初始化,调用getInstance才会去加载SingletonLoader类,确保了线程安全、单例的唯一性。
由此可见,这种写法不执行getInstance()则不被实例化,可以执行该类其他静态方法,避免资源浪费(优点);
但第一次加载速度肯定不够快(缺点)。

总结

其实不管哪种实现方式,其核心思想是一样的,私有化构造方法,然后通过静态方法返回唯一对象实例,同时保证线程安全。

具体使用哪种方式要看应用场景。有的场景适合饿汉式,有的对资源加载有要求的可以采用静态内部类方式。

其实Android系统中就有很多单例模式的运用,包括日常的APP开发中的Application也是常见的单例模式。还有很多Context调用的系统服务等,比如LayoutInflater服务。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1447910.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ARMv8-AArch64 的异常处理模型详解之异常处理概述Handling exceptions

异常处理模型详解之异常处理概述 一,异常处理相关概念二,异常处理概述 一,异常处理相关概念 在介绍异常处理之前,有必要了解一些关于异常处理状态的术语: 当处理器响应一个异常时,我们称该异常被获取了&a…

【C++入门语法】1.变量的世界

​ 欢迎来到C的世界!在这篇文章中,我们将一起探索C编程中的基本概念——变量。变量是程序设计中非常重要的一部分,它们是存储数据的容器,让我们的程序能够记住和操作这些信息。 什么是变量? 变量是一个标识符&#x…

Web前端开发

一、概述 1.1 什么是HTML、CSS&#xff1f; 二、HTML 2.1 HTML快速入门 2.2 基础标签和样式 2.2.1 标题 &#xff08;1&#xff09;标题排版 输入&#xff01;加回车&#xff0c;直接生成HTML基本结构标签 。 <!-- 声明当前文档类型 --> <!DOCTYPE html> &l…

windows@命令行映射磁盘驱动器若干方法@开机自动映射网络磁盘

文章目录 windows映射网络磁盘驱动器资源管理器中GUI方式创建命令行方式创建命令行列出驱动器列表删除取消映射持久化配置映射&#x1f47a;记住凭证 FAQ开机自启登录系统后自动挂载&#x1f47a;[以alist webdav 挂载为例]分析对策延迟挂载&#x1f47a;Note 访问已经挂载网络…

【牛客面试必刷TOP101】Day19.BM24 二叉树的中序遍历和BM26 求二叉树的层序遍历

作者简介&#xff1a;大家好&#xff0c;我是未央&#xff1b; 博客首页&#xff1a;未央.303 系列专栏&#xff1a;牛客面试必刷TOP101 每日一句&#xff1a;人的一生&#xff0c;可以有所作为的时机只有一次&#xff0c;那就是现在&#xff01;&#xff01;&#xff01;&…

2024年【陕西省安全员A证】考试试卷及陕西省安全员A证模拟考试题库

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 陕西省安全员A证考试试卷根据新陕西省安全员A证考试大纲要求&#xff0c;安全生产模拟考试一点通将陕西省安全员A证模拟考试试题进行汇编&#xff0c;组成一套陕西省安全员A证全真模拟考试试题&#xff0c;学员可通过…

【JAVA WEB】JavaScript(WebAPI)--DOM基本概念 获取元素 点击事件 键盘事件

目录 什么是WebAPI DOM的基本概念 DOM是什么 DOM树 获取元素 querySelector querySelectorAll 事件 事件初识 基本概念 事件三要素 点击事件 键盘事件 什么是WebAPI 前端学习的 JS 分成三个大的部分 ECMAScript&#xff1a;基础语法部分DOM API&#xff1a;操作…

算法刷题:快乐数

快乐数 .习题链接题目题目解析初始值算法原理我的答案 . 习题链接 快乐数 题目 编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」 定义为&#xff1a; 对于一个正整数&#xff0c;每一次将该数替换为它每个位置上的数字的平方和。 然后重复这个过程直到这个数变为 1…

数学实验第三版(主编:李继成 赵小艳)课后练习答案(九)(1)(2)

实验九&#xff1a;线性函数极值求解 练习一 1.求解线性规划问题&#xff1a; &#xff08;1&#xff09;max z3,s.t. clc;clear; %采用软件解法 c[-3,-1]; a[-1,1;1,-2;3,2]; b[2;2;14]; [x,min]linprog(c,a,b)找到最优解。 x 4 1 min -13 题上要求的是最大值&#…

二叉树的垂直遍历

1.题目 这道题是2024-2-13的签到题&#xff0c;题目难度为困难。 考察的知识点是DFS算法和自定义排序。 题目链接&#xff1a;二叉树的垂直遍历 给你二叉树的根结点 root &#xff0c;请你设计算法计算二叉树的 垂序遍历 序列。 对位于 (row, col) 的每个结点而言&#xff…

Spark编程实验六:Spark机器学习库MLlib编程

目录 一、目的与要求 二、实验内容 三、实验步骤 1、数据导入 2、进行主成分分析&#xff08;PCA&#xff09; 3、训练分类模型并预测居民收入 4、超参数调优 四、结果分析与实验体会 一、目的与要求 1、通过实验掌握基本的MLLib编程方法&#xff1b; 2、掌握用MLLib…

软件实例分享,宠物店兽医电子处方开单系统软件教程

软件实例分享&#xff0c;宠物店兽医电子处方开单系统软件教程 一、软件教程问答 以下教程以 佳易王宠物店兽医电子处方软件V16.0为例说明 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 问&#xff1a;宠物医院电子处方单子使用的纸张大小是多少&…

19 删除链表的倒数第 N 个结点

19. 删除链表的倒数第 N 个结点 中等 相关标签 相关企业 提示 给你一个链表&#xff0c;删除链表的倒数第 n 个结点&#xff0c;并且返回链表的头结点。 这段代码使用了双指针的方法&#xff0c;其中一个指针先走 n 步&#xff0c;然后两个指针一起走&#xff0c;直到第一…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之LoadingProgress组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之LoadingProgress组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、LoadingProgress组件 用于显示加载动效的组件。 子组件 无 接口 L…

【Linux学习】生产者-消费者模型

目录 22.1 什么是生产者-消费者模型 22.2 为什么要用生产者-消费者模型? 22.3 生产者-消费者模型的特点 22.4 BlockingQueue实现生产者-消费者模型 22.4.1 实现阻塞队列BlockQueue 1) 添加一个容器来存放数据 2)加入判断Blocking Queue情况的成员函数 3)实现push和pop方法 4)完…

使用word2vec+tensorflow自然语言处理NLP

目录 介绍&#xff1a; 搭建上下文或预测目标词来学习词向量 建模1&#xff1a; 建模2&#xff1a; 预测&#xff1a; 介绍&#xff1a; Word2Vec是一种用于将文本转换为向量表示的技术。它是由谷歌团队于2013年提出的一种神经网络模型。Word2Vec可以将单词表示为高维空间…

JAVA-多进程开发-创建等待进程

前言 在项目中&#xff0c;为了实现“并发编程”&#xff08;同时执行多个任务&#xff09;&#xff0c;就引入了“多进程编程”&#xff0c;把一个很大的任务&#xff0c;拆分成若干个很小的任务&#xff0c;创建多个进程&#xff0c;每个进程分别负责其中的一部分任务。 这也…

Java实现中学生家校互联系统 JAVA+Vue+SpringBoot+MySQL

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 学生管理模块2.2 课堂表现模块2.3 考试成绩模块2.4 家校留言模块2.5 校园通知模块 三、系统设计3.1 用例设计3.2 实体类设计3.2.1 课堂表现实体类设计3.2.2 考试成绩实体类设计3.2.3 家校留言实体类设计3.2.4 校园通知实…

虚拟人专题报告:虚拟人深度产业分析报告

今天分享的是虚拟人系列深度研究报告&#xff1a;《虚拟人专题报告&#xff1a;虚拟人深度产业分析报告》。 &#xff08;报告出品方&#xff1a;Q量子位&#xff09; 报告共计&#xff1a;18页 技术背景 虚拟数字人指存在于非物理世界中&#xff0c;由计算机图形学、图形渲…

【Vue】工程化开发脚手架Vue CLI

&#x1f4dd;个人主页&#xff1a;五敷有你 &#x1f525;系列专栏&#xff1a;Vue⛺️稳重求进&#xff0c;晒太阳 工程化开发&脚手架Vue CLI 基本介绍 Vue Cli是Vue官方提供的一个全局命令工具 可以帮助我们快速创建一个开发Vue项目的标准化基础架子【集成了we…