likes
comments
collection
share

「聊设计模式」之单例模式(Singleton)

作者站长头像
站长
· 阅读数 12

🏆本文收录于《聊设计模式》专栏,专门攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎持续关注&&收藏&&订阅!


前言

  设计模式是面向对象编程中非常重要的一部分,设计模式可以帮助我们更好的组织代码,使代码更加易于维护、拓展和重构。本文将会介绍单例模式的概念以及如何在Java语言中实现单例模式。

摘要

  单例模式是一种创建型设计模式,在一个系统中,保证一个类仅有一个实例,并提供一个全局的访问点。

单例模式

  在面向对象编程中,创建一个类的实例是很常见的。但有时,我们需要模式保证在一个程序中只有一个实例,这是单例模式的出现背景。单例模式是一种创建型设计模式,意味着它解决了一个特定问题,即如何在系统中只有一个实例,并提供一个全局的访问点。

结构

单例模式的主要角色如下。

单例类:包含一个实例且能自行创建这个实例的类。 访问类:使用单例的类。

如下是单例模式的UML类图:

「聊设计模式」之单例模式(Singleton)

单例模式优点

  • 在一个系统中只有一个实例,减少了内存开销以及对象的复杂性。
  • 提供了一个全局的访问点,方便了使用和管理。

单例模式缺点

  • 单例模式需要在程序运行之前就创建好实例,对于那些复杂并且需要依赖外部环境的单例模式(比如需要从网络获取配置文件的单例模式),会增加程序的复杂度。
  • 单例模式会在整个程序的生命周期中存在,如果不合理的使用了单例模式,会导致内存泄漏以及影响垃圾回收。

在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 懒汉式单例模式

  饿汉式单例模式和懒汉式单例模式都是用于实现对象的单例模式,其差异在于对象的创建时间和线程安全性。

  1. 饿汉式单例模式

  在程序启动时就创建了单例对象,因此被称为“饿汉式”。使用时直接返回该对象,不存在线程安全问题。但是,如果该对象在程序运行时没有被使用,会造成内存浪费。

  1. 懒汉式单例模式

  在需要时才创建单例对象,因此被称为“懒汉式”。单例对象在第一次使用时才被创建,也就是说,该对象可能会在多个线程同时调用时被创建,因此需要考虑线程安全问题。可以使用同步锁或者双重检查锁定等方式来保证线程安全性。但是,因为需要在每次调用时创建对象,会造成一定的性能损失。

  综上,饿汉式单例模式在简单性和线程安全性方面较为优越,但是会浪费内存;懒汉式单例模式可以节省内存,但需要考虑线程安全性和性能问题。通过具体的使用场景和需求来选择合适的单例模式实现。

测试用例

下面是我们的测试用例:

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)

  在测试用例中,我们创建了两个Singleton实例,然后通过比较它们的地址来判断它们是否是同一个对象。当运行测试用例时,控制台会输出true,表示两个实例是同一个对象。

小结

  本文主要介绍了单例模式的概念以及如何在Java语言中实现单例模式。单例模式可以保证一个程序中只有一个实例,并提供了一个全局的访问点,这样可以方便我们对对象进行管理和使用。在Java语言中,我们可以通过饿汉式单例模式和懒汉式单例模式来实现单例模式,但需要注意线程安全性和内存泄漏问题。

附录源码

  如上涉及代码均已上传同步在GitHub,提供给同学们参考性学习。

总结

  单例模式是一种常见的创建型设计模式,可以保证在一个程序中只有一个实例,并提供了一个全局的访问点。在Java语言中,我们可以通过两种方式来实现单例模式,即饿汉式单例模式和懒汉式单例模式。但需要注意线程安全性和内存泄漏问题。

☀️建议/推荐你

  如果想系统性的全面学习设计模式,建议小伙伴们直接毫无顾忌的关注这个专栏《聊设计模式》,无论你是想提升自己的编程技术,还是渴望更好地理解代码背后的设计思想,本专栏都会为你提供实用的知识和启发,帮助你更好地解决日常开发中的挑战,将代码变得更加优雅、灵活和可维护!

📣关于我


「聊设计模式」之单例模式(Singleton)

转载自:https://juejin.cn/post/7280734373233098764
评论
请登录