常见单例模式详解

单例模式是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.hqwc.cn/news/469725.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java 基于 SpringBoot+Vue 的智慧外贸平台的研究与实现,附源码

博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…

基于Transformer的机器学习模型的主动学习

主动学习和基于Transformer的机器学习模型的结合为有效地训练深度学习模型提供了强有力的工具。通过利用主动学习,数据科学家能够减少训练模型所需的标记数据的数量,同时仍然达到高精度。本文将探讨基于Transformer的机器学习模型如何在主动学习环境中使…

嵌入式Linux中系统调试常用命令

在 Linux 中,获取系统信息和监控系统资源的操作是非常常见的任务。以下是一些常用的命令和工具,以及一些相关的系统文件,用于获取 Linux 系统信息和监控系统资源。 1. 基本系统信息 uname 命令 uname 命令用于显示系统信息。 查看内核版本&…

【Python】高级数据类型

🚩 WRITE IN FRONT 🚩 🔎 介绍:"謓泽"正在路上朝着"攻城狮"方向"前进四" 🔎🏅 荣誉:2021|2022年度博客之星物联网与嵌入式开发TOP5|TOP4、2021|2222年获评…

洛谷C++简单题小练习day11—字母转换,分可乐两个小程序

day11--字母转换--2.14 习题概述 题目描述 输入一个小写字母&#xff0c;输出其对应的大写字母。例如输入 q[回车] 时&#xff0c;会输出 Q。 代码部分 #include<bits/stdc.h> using namespace std; int main() { char n;cin>>n;cout<<char(n-32)<…

C++:Level1阶段测试

总结。 只要你看过我的文章&#xff0c;哪怕只是一半&#xff0c;一定能够过关&#xff01; 准备好开始测试氻吗&#xff1f; 选择题&#xff0c;每题4分&#xff0c;共40分 1、 DevC的项目创建按钮是_____ A、文件[F]” → “新建[N]” → “项目[P]... B、工具[T]” → …

TMGM外汇平台,澳网的官方赞助商

TMGM澳洲总部公司很高兴地通知大家&#xff0c;为了带给客户们更优质的交易环境体验&#xff0c;我们预计将于2024年2月上线MT5交易平台TMGM作为2021-2023 澳网的官方赞助商&#xff0c;能见证郑钦文取得如此的成就由衷的为她感到骄傲&#xff01;本届澳网&#xff0c;TMGM邀请…

操作系统(14)----文件系统的结构

目录 一.文件系统的层次结构 1.用户接口&#xff1a; 2.文件目录系统&#xff1a; 3.存取控制模块&#xff1a; 4.逻辑文件系统与文件信息缓冲区&#xff1a; 5.物理文件系统&#xff1a; 二.文件系统的全局结构 1.文件系统在外存中的结构 &#xff08;1&#xff09;物…

算法学习——LeetCode力扣贪心篇2

算法学习——LeetCode力扣贪心篇2 45. 跳跃游戏 II 45. 跳跃游戏 II - 力扣&#xff08;LeetCode&#xff09; 描述 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说&#xff0c;如果你在 num…

算法详解(力扣141——环形链表系列)

博主ID&#xff1a;代码小豪 文章目录 环形链表环形链表的性质分析快慢指针法指针的追及相遇问题 环形链表&#xff08;2&#xff09; 环形链表 先来看看环形链表的原题&#xff1a; 中间的部分叙述有点繁杂&#xff0c;简单来概括就是&#xff0c;假如有一个节点&#xff0c…

Java微服务学习Day2

文章目录 Nacos配置管理统一配置管理配置热更新![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/c8a2d17baeef411980b44b432eb9692a.png)配置共享搭建Nacos集群 Feign远程调用介绍自定义配置性能优化最佳实践 Gateway服务网关介绍搭建网关服务路由断言工厂路由过滤器…

【Django】Django内建用户系统

Django内建用户系统 14.1 Django中的用户认证 Django带有一个用户认证系统系统&#xff0c;它处理用户用户账号、组、权限以及基于cookie的用户会话。 用户可以直接使用Django自带的用户表。 官方文档&#xff1a;https://docs.djangoproject.com/zh-hans/2.2/topics/auth/ …