设计模式从入门到精通之(三)单例模式

单例模式:只留一份独特的存在

在现代软件设计中,有些对象是必须确保"独一无二"的,比如程序中的配置管理器、线程池、数据库连接等。如果允许这些对象被反复创建,不仅会浪费系统资源,还可能导致程序逻辑出错。今天我们要聊的单例模式,正是用来解决这些问题的。


1. 什么是单例模式?

单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例,并且提供全局访问点来获取该实例。简单来说,单例模式就是全球通用的唯一代言人

在实际开发中,单例模式常用于:

  1. 配置管理:程序中的全局配置只需要一个实例。
  2. 资源共享:某些资源(如线程池、日志系统)必须全局共享。
  3. 控制实例数量:限制某些类的实例数量,避免资源浪费。

2. 用现实中的故事引出单例模式

想象你在一个学校任教。学校的公告栏是全校师生获取通知的唯一地方,所有的信息都必须通过公告栏发布。假如学校允许多个公告栏存在,那可能会导致混乱,比如不同公告栏上的信息不一致。

因此,学校必须确保公告栏唯一性 ,而且所有人都知道它的位置。这就是单例模式的思想:一个类只能有一个实例,而且这个实例对全局都是可见的。


3. 单例模式的代码实现

下面我们以公告栏为例,来实现单例模式。

3.1 饿汉式单例

饿汉式单例在类加载时就完成实例化,因此线程安全,但如果实例从未被使用,会浪费内存。

java 复制代码
class BulletinBoard {
    // 1. 提前创建唯一实例
    private static final BulletinBoard instance = new BulletinBoard();

    // 2. 私有构造方法,防止外部实例化
    private BulletinBoard() {
        System.out.println("公告栏已初始化");
    }

    // 3. 提供全局访问点
    public static BulletinBoard getInstance() {
        return instance;
    }

    public void postMessage(String message) {
        System.out.println("公告:" + message);
    }
}

public class Main {
    public static void main(String[] args) {
        BulletinBoard board = BulletinBoard.getInstance();
        board.postMessage("明天学校停电,请提前做好准备。");
    }
}

运行结果:

复制代码
公告栏已初始化
公告:明天学校停电,请提前做好准备。
3.2 懒汉式单例

懒汉式单例在第一次调用时创建实例,节省资源,但必须考虑线程安全问题。

java 复制代码
class BulletinBoard {
    // 1. 声明静态变量,但不初始化
    private static BulletinBoard instance;

    // 2. 私有构造方法
    private BulletinBoard() {
        System.out.println("公告栏已初始化");
    }

    // 3. 提供线程安全的全局访问点
    public static synchronized BulletinBoard getInstance() {
        if (instance == null) {
            instance = new BulletinBoard();
        }
        return instance;
    }

    public void postMessage(String message) {
        System.out.println("公告:" + message);
    }
}
3.3 双重检查锁(推荐)

双重检查锁结合了饿汉式和懒汉式的优点,既保证了线程安全,又提升了性能。

java 复制代码
class BulletinBoard {
    private static volatile BulletinBoard instance;

    private BulletinBoard() {
        System.out.println("公告栏已初始化");
    }

    public static BulletinBoard getInstance() {
        if (instance == null) {
            synchronized (BulletinBoard.class) {
                if (instance == null) {
                    instance = new BulletinBoard();
                }
            }
        }
        return instance;
    }

    public void postMessage(String message) {
        System.out.println("公告:" + message);
    }
}

4. 单例模式的优缺点

优点:

  1. 全局唯一性:确保一个类只有一个实例,节省资源。
  2. 全局访问:为程序提供统一的访问点,方便管理。
  3. 延迟初始化(懒汉式):提升性能,减少启动时的资源开销。

缺点:

  1. 不易扩展:由于单例模式强制只有一个实例,难以被继承或修改。
  2. 多线程问题:懒汉式实现需要小心处理线程安全。
  3. 隐藏依赖:过度使用单例可能让代码之间的依赖关系不清晰,增加维护难度。

5. 总结

单例模式看似简单,却是软件设计中的一颗"小而美"的明珠。在需要确保全局唯一性的时候,单例模式是非常高效的解决方案。但它也不是万能的,滥用单例可能导致代码难以测试和维护。

下一篇专栏中,我们将介绍一种和工厂模式密切相关的模式:建造者模式,看看如何一步步优雅地构建复杂对象。


思考问题:

在双重检查锁的实现中,为什么instance需要用volatile关键字修饰?如果省略,会产生什么问题?欢迎在评论区讨论!

相关推荐
卡尔特斯28 分钟前
Android Kotlin 项目代理配置【详细步骤(可选)】
android·java·kotlin
白鲸开源29 分钟前
Ubuntu 22 下 DolphinScheduler 3.x 伪集群部署实录
java·ubuntu·开源
ytadpole37 分钟前
Java 25 新特性 更简洁、更高效、更现代
java·后端
纪莫1 小时前
A公司一面:类加载的过程是怎么样的? 双亲委派的优点和缺点? 产生fullGC的情况有哪些? spring的动态代理有哪些?区别是什么? 如何排查CPU使用率过高?
java·java面试⑧股
JavaGuide2 小时前
JDK 25(长期支持版) 发布,新特性解读!
java·后端
用户3721574261352 小时前
Java 轻松批量替换 Word 文档文字内容
java
白鲸开源2 小时前
教你数分钟内创建并运行一个 DolphinScheduler Workflow!
java
晨米酱2 小时前
JavaScript 中"对象即函数"设计模式
前端·设计模式
Java中文社群3 小时前
有点意思!Java8后最有用新特性排行榜!
java·后端·面试
代码匠心3 小时前
从零开始学Flink:数据源
java·大数据·后端·flink