「聊设计模式」之单例模式(Singleton)
🏆本文收录于《聊设计模式》专栏,专门攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎持续关注&&收藏&&订阅!
大家下午好,我是bug菌,今天我们继续聊设计模式。
前言
设计模式是面向对象编程中非常重要的一部分,设计模式可以帮助我们更好的组织代码,使代码更加易于维护、拓展和重构。本文将会介绍单例模式的概念以及如何在Java语言中实现单例模式。
摘要
单例模式是一种创建型设计模式,在一个系统中,保证一个类仅有一个实例,并提供一个全局的访问点。
单例模式
在面向对象编程中,创建一个类的实例是很常见的。但有时,我们需要模式保证在一个程序中只有一个实例,这是单例模式的出现背景。单例模式是一种创建型设计模式,意味着它解决了一个特定问题,即如何在系统中只有一个实例,并提供一个全局的访问点。
结构
单例模式的主要角色如下。
单例类:包含一个实例且能自行创建这个实例的类。
访问类:使用单例的类。
如下是单例模式的UML类图:
模式优缺点
单例模式优点
- 在一个系统中只有一个实例,减少了内存开销以及对象的复杂性。
- 提供了一个全局的访问点,方便了使用和管理。
单例模式缺点
- 单例模式需要在程序运行之前就创建好实例,对于那些复杂并且需要依赖外部环境的单例模式(比如需要从网络获取配置文件的单例模式),会增加程序的复杂度。
- 单例模式会在整个程序的生命周期中存在,如果不合理的使用了单例模式,会导致内存泄漏以及影响垃圾回收。
应用场景
单例模式适用于以下场景:
- 系统只需要一个实例对象,例如系统的日志文件、全局配置信息等。
- 需要频繁创建和销毁对象,而创建和销毁对象又非常耗时,影响系统性能。
- 需要每次获取同一个对象,保证数据操作的一致性。
总的来说,单例模式适用于需要频繁使用的对象,且保证全局唯一的情况下使用。它可以提高系统的性能、减少内存使用和避免数据不一致的情况。
模式实现
在Java语言中,我们可以通过两种方式来实现单例模式:
饿汉式-单例模式
饿汉式单例模式就是在程序启动时就创建好实例,通常来说,在类的定义中就已经创建好实例了,如下所示:
package com.example.javaDesignPattern.singleton;
/**
* 饿汉式单例模式
*
* @author bug菌
* @version 1.0
* @date 2023/9/19 10:39
*/
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
public static Singleton getInstance() {
return INSTANCE;
}
private Singleton() {}
}
在上面的代码中,我们可以看到,Singleton
类中有一个静态的私有变量INSTANCE
,用来保存单例实例。在类初始化时,INSTANCE
变量会被立即实例化,并通过getInstance
方法获取。由于INSTANCE
变量是静态的,所以它仅会在类的首次加载时初始化一次,保证了在多线程环境下的线程安全性。
懒汉式-单例模式
该模式的特点是类加载时没有生成单例,只有当第一次调用 getlnstance 方法时才去创建这个单例。代码如下:
package com.example.javaDesignPattern.singleton;
/**
* 懒汉式单例模式
*
* @author bug菌
* @version 1.0
* @date 2023/9/19 10:39
*/
public class Singleton {
private static Singleton INSTANCE = null;
public static synchronized Singleton getInstance() {
if (INSTANCE == null) {
INSTANCE = new Singleton();
}
return INSTANCE;
}
private Singleton() {
}
}
在上面的代码中,我们可以看到,在getInstance
方法中,如果当前INSTANCE
变量为null
,那么我们就会创建一个新的实例,否则直接返回INSTANCE
即可。但要注意的是,在多线程环境中,由于getInstance
方法是一个公共的静态方法,所以我们需要通过synchronized
保证线程安全性。
代码方法介绍
在上面的代码中,有一些重要的方法需要我们进行介绍:
- 静态变量:即在类定义中定义的static类型的变量,这些变量不属于任何一个实例,而是属于类本身,不管这个类有多少个实例,这些变量只初始化一次。
- 静态方法:即在类定义中定义的static类型的方法,这些方法不属于任何一个实例,而是属于类本身,可以直接通过类名调用,不需要创建实例。
- synchronized关键字:即锁定对象,保证在同一时刻最多只有一个线程访问共享资源,并不代表是同步方法一定是线程安全的。
饿汉式 VS 懒汉式
饿汉式单例模式和懒汉式单例模式都是用于实现对象的单例模式,其差异在于对象的创建时间和线程安全性。
- 饿汉式单例模式
在程序启动时就创建了单例对象,因此被称为“饿汉式”。使用时直接返回该对象,不存在线程安全问题。但是,如果该对象在程序运行时没有被使用,会造成内存浪费。
- 懒汉式单例模式
在需要时才创建单例对象,因此被称为“懒汉式”。单例对象在第一次使用时才被创建,也就是说,该对象可能会在多个线程同时调用时被创建,因此需要考虑线程安全问题。可以使用同步锁或者双重检查锁定等方式来保证线程安全性。但是,因为需要在每次调用时创建对象,会造成一定的性能损失。
综上,饿汉式单例模式在简单性和线程安全性方面较为优越,但是会浪费内存;懒汉式单例模式可以节省内存,但需要考虑线程安全性和性能问题。通过具体的使用场景和需求来选择合适的单例模式实现。
测试用例
下面是我们的测试用例:
package com.example.javaDesignPattern.singleton;
/**
* @author bug菌
* @version 1.0
* @date 2023/9/19 10:39
*/
public class SingletonTest {
public static void main(String[] args) {
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
System.out.println(s1 == s2);
}
}
执行结果如下:
在测试用例中,我们创建了两个Singleton
实例,然后通过比较它们的地址来判断它们是否是同一个对象。当运行测试用例时,控制台会输出true
,表示两个实例是同一个对象。
小结
本文主要介绍了单例模式的概念以及如何在Java语言中实现单例模式。单例模式可以保证一个程序中只有一个实例,并提供了一个全局的访问点,这样可以方便我们对对象进行管理和使用。在Java语言中,我们可以通过饿汉式单例模式和懒汉式单例模式来实现单例模式,但需要注意线程安全性和内存泄漏问题。
附录源码
如上涉及代码均已上传同步在GitHub,提供给同学们参考性学习。
总结
单例模式是一种常见的创建型设计模式,可以保证在一个程序中只有一个实例,并提供了一个全局的访问点。在Java语言中,我们可以通过两种方式来实现单例模式,即饿汉式单例模式和懒汉式单例模式。但需要注意线程安全性和内存泄漏问题。
☀️建议/推荐你
如果想系统性的全面学习设计模式,建议小伙伴们直接毫无顾忌的关注这个专栏《聊设计模式》,无论你是想提升自己的编程技术,还是渴望更好地理解代码背后的设计思想,本专栏都会为你提供实用的知识和启发,帮助你更好地解决日常开发中的挑战,将代码变得更加优雅、灵活和可维护!
最后,如果这篇文章对你有所帮助,帮忙给作者来个一键三连,关注、点赞、收藏,您的支持就是我坚持写作最大的动力。
同时欢迎大家关注公众号:「猿圈奇妙屋」 ,以便学习更多同类型的技术文章,免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板、技术文章Markdown文档等海量资料。
📣关于我
我是bug菌,CSDN | 掘金 | infoQ | 51CTO 等社区博客专家,历届博客之星Top30,掘金年度人气作者Top40,51CTO年度博主Top12,华为云 | 阿里云| 腾讯云等社区优质创作者,全网粉丝合计15w+ ;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板等海量资料。
- 点赞
- 收藏
- 关注作者
评论(0)