常见单例模式详解

单例模式是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服务。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数据库从入门到精通(一)数据库基础操作

mysql数据库基础操作 cmd下启动mysql数据库操作命令数据库重要的删除操作数据库增删改查操作插入数据更新数据删除数据查询数据查询指定记录in查询满足指定范围之内的条件记录not in查询不在指定范围之内的条件记录带between and 的范围查询带like的字符匹配查询(d%以d开头,%d以…

建模语言CellML初步

文章目录 简介洛伦兹吸引子仿真 简介 CellML是主打计算生理学的一个编程语言,擅长处理微分方程问题,并且内置了单位系统,是细胞层次的建模工具。openCOR为其运行环境,提供了舒适的代码编辑窗口,以及一系列IDE工具&…

【lesson53】线程控制

文章目录 线程控制 线程控制 线程创建 代码: 运行代码: 强调一点,线程和进程不一样,进程有父进程的概念,但在线程组里面,所有的线程都是对等关系。 错误检查: 传统的一些函数是,成功返回0&…

TeamCity创建git项目Timed out 超时的一个解决办法

问题: 当自己: ping github.com从本地推送到远程仓库浏览器浏览www.github.com ——都没有问题 但是在teamcity创建工程的时候就超时: 或者多试几次,终于成功了,然后构建的时候半途超时报错。。。。。 一种解决办…

Spring GateWay

概述简介 能干什么 反向代理 鉴权 流量控制 熔断 日志监控 Spring Cloud Gateway 与Zuul的区别 在SpringCloud Finchley正式版之前,Spring Cloud推荐的网关是 Netflix提供的Zuul: 1、Zuul 1.x,是一个基于阻塞Ⅳ/O的APl Gateway 2、Zuul 1.x基于Servl…

linux系统zabbix监控配置钉钉告警

zabbix配置钉钉告警 配置钉钉告警环境准备配置钉钉脚本文件钉钉日志目录编写脚本浏览器配置钉钉告警中文消息告警模版为用户添加报警媒介添加监控项》添加触发器》 添加玩监控项和触发器后添加动作 配置钉钉告警 环境准备 创建钉钉内部群创建自定义机器人记录加签地址和webho…

thinkphp5.0提示不支持redis,not support: redis

安装PHP扩展 例如宝塔,其他环境请用命令行,安装 redis配置完成以后,修改php.ini把redis扩展打开即可,重启环境

【AI视野·今日CV 计算机视觉论文速览 291期】Wed, 17 Jan 2024

AI视野今日CS.CV 计算机视觉论文速览 Wed, 17 Jan 2024 Totally 182 papers 👉上期速览✈更多精彩请移步主页 Daily Computer Vision Papers MultiPLY: A Multisensory Object-Centric Embodied Large Language Model in 3D World Authors Yining Hong, Zishuo Zhe…

深入探索Pandas读写XML文件的完整指南与实战read_xml、to_xml【第79篇—读写XML文件】

深入探索Pandas读写XML文件的完整指南与实战read_xml、to_xml XML(eXtensible Markup Language)是一种常见的数据交换格式,广泛应用于各种应用程序和领域。在数据处理中,Pandas是一个强大的工具,它提供了read_xml和to…

第二十八回 施恩重霸孟州道 武松醉打蒋门神-可用于生产环境的Python Web框架:Pyramid

施恩给武松讲了他的烦心事,他在快活林的酒肉店被蒋门神霸占了。希望武松能帮他出气。施恩的父亲也从屏风后走出来,让施恩拜武松为兄长。 武松要去打蒋门神,跟施恩约好了“无三不过望”,望子就是酒旗,意思看到酒旗就要…

H12-821_74

74.在某路由器上查看LSP,看到如下结果: A.发送目标地址为3.3.3.3的数据包时,打上标签1026,然后发送。 B.发送目标地址为4.4.4.4的数据包时,不打标签直接发送。 C.当路由器收到标签为1024的数据包,将把标签…

【JavaEE】_HTTP请求与响应

目录 1. HTTP协议 1.1 HTTP简介 1.2 Fiddler 2. HTTP请求 2.1 首行 2.2 请求头(header) 2.3 空行 2.4 正文(body) 3. HTTP响应 3.1 首行 3.2 响应头(header) 3.3 空行 3.4 正文(bo…

跟廖雪峰老师学习Git(持续更新)

Git简介 创建版本库 第一步,创建一个新目录 第二步,通过git init变成Git可以管理的仓库 把文件添加到文本库,不要使用Windows自带的记事本! 我用的是VS code 创建readme.txt 放入库中 commit可以一次提交很多文件&#xff0…

酒店押金预授权怎么开通?微信酒店押金+房态+门锁关联 +电子押金单 解决方案

一、酒店押金管理有哪些? 1.渠道有银行预授权 2.微信押金支付 3.酒店押金系统 4.支付押金管理 二、银行预授权模式 酒店押金预授权通常是在客人办理入住时进行的,酒店会要求客人提供信用卡或借记卡的卡号、有效期、持卡人姓名等信息,然后…

Django学习全纪录:Django开发环境的搭建

导言 对于Django,它是Python的一个开发框架,之前系统地学习过。遗憾的是,对于一些遇到的问题,没有及时地记录下来。因此,我将它重新捡起,进行学习和实践。从搭建环境开始,重新去学习它&#xff…

应用进程跨越网络的通信

目录 1 系统调用和应用编程接口 应用编程接口 API 几种应用编程接口 API 套接字的作用 几种常用的系统调用 1. 连接建立阶段 2. 传送阶段 3. 连接释放阶段 1 系统调用和应用编程接口 大多数操作系统使用系统调用 (system call ) 的机制在应用程序和操作系统之间传递控制…

Kafka 之生产者(Producer)

目录 一. 前言 二. 生产消息 三. 幂等和事务 四. send() 发送消息 五. 原理解析 一. 前言 Kafka生产者是一个应用程序,它负责向 Kafka 主题发送消息。这些消息可以用于多种目的,如记录用户活动、收集物联网设备数据、保存日志消息或缓存即将写入数据…

66万个 全国行政区划代码表

66万个全国各级行政区划代码表 提供的数据一览 简介 一共有66万个全国各级行政区划,一共有5个级别的行政单位级别 表格头部数据 表格尾部数据 全国行政单位各省份数量统计 数据下载地址 数据整理不易 百度云盘 链接: https://pan.baidu.com/s/1o1C2piYj2wu…

C#,数值计算,矩阵的行列式(Determinant)、伴随矩阵(Adjoint)与逆矩阵(Inverse)的算法与源代码

本文发布矩阵(Matrix)的一些初级算法。 一、矩阵的行列式(Determinant) 矩阵行列式是指矩阵的全部元素构成的行列式,设A(a)是数域P上的一个n阶矩阵,则所有A(a)中的元素组成的行列式称为矩阵A的行列式&…

仰暮计划|“​他们艰苦半生,但真的希望祖国安祥,山河无恙”

自述,自赎 我没有在那个年代生活过,我一出生就是盛世中国,看遍了祖国的大好河山。但我没想到,走了这么远的路,吃了这么多的苦的爷爷会一直跟我说“不是国家不好,只是中国的钱拿去还债了,过了那…