当前位置:首页 > 技术 > 正文内容

设计模式精讲:单例模式的多种实现与对比

访客 技术 2026年7月6日 1

单例模式是设计模式体系中最基础也最实用的一种,几乎在所有项目中都能找到它的身影。其核心目标是确保类在全局范围内只有一个实例,并提供统一的访问入口。虽然概念简单,但实现方式却有不少变种,以下逐一分析七种常见方案。

1. 饿汉式(静态常量)

这是最直接的实现方式,在类加载的时候就完成实例化,无论后续是否使用。

public class EagerSingleton {
    private static final EagerSingleton INSTANCE = new EagerSingleton();

    private EagerSingleton() {}

    public static EagerSingleton getInstance() {
        return INSTANCE;
    }
}

特点:线程安全(由类加载机制保证),但无懒加载效果。若类消耗资源且长时间未使用,会浪费内存。

适用场景:实例较小、实例化开销不高且频繁需要使用的类。

2. 懒汉式(非线程安全)

与饿汉式相反,实例仅在首次调用 getInstance() 时创建,实现懒加载。

public class LazySingleton {
    private static LazySingleton instance;

    private LazySingleton() {}

    public static LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}

问题:多线程环境下,多个线程可能同时进入 if (instance == null) 判断,导致创建多个实例,破坏单例。

3. 懒汉式 + 同步方法

getInstance() 方法上添加 synchronized 关键字解决线程安全问题。

public class LazySyncSingleton {
    private static LazySyncSingleton instance;

    private LazySyncSingleton() {}

    public static synchronized LazySyncSingleton getInstance() {
        if (instance == null) {
            instance = new LazySyncSingleton();
        }
        return instance;
    }
}

缺点:每次调用方法都需要获取锁,性能低下,实际上只有首次创建时才需要加锁。

4. 双重检查锁(Double-Checked Locking)

结合 synchronized 两次检查,只在实例为空时加锁,提升性能。

public class DclSingleton {
    private static DclSingleton instance;

    private DclSingleton() {}

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

隐患instance = new DclSingleton() 在 JVM 中并非原子操作,可能被重排序,导致其他线程拿到未完全初始化的实例。

5. 双重检查锁 + volatile

使用 volatile 关键字禁止指令重排序,彻底解决上述隐患。

public class DclVolatileSingleton {
    private static volatile DclVolatileSingleton instance;

    private DclVolatileSingleton() {}

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

这是懒加载与线程安全兼顾的经典实现。

6. 静态内部类(Holder模式)

利用 Java 内部类的延迟加载机制实现线程安全的单例。

public class HolderSingleton {
    private HolderSingleton() {}

    private static class SingletonHolder {
        private static final HolderSingleton INSTANCE = new HolderSingleton();
    }

    public static HolderSingleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

原理:静态内部类只在首次调用 getInstance() 时才会被加载并初始化,JVM 保障初始化过程的线程安全。兼具懒加载和高性能。

7. 枚举方式

《Effective Java》强烈推荐的方案,代码简洁且天然防序列化、反射攻击。

public enum EnumSingleton {
    INSTANCE;

    EnumSingleton() {
        System.out.println("实例化");
    }

    public static EnumSingleton getInstance() {
        return INSTANCE;
    }
}

缺点:无法实现懒加载(枚举常量在类加载时即会初始化)。

总结

实现方式线程安全懒加载性能推荐度
饿汉式⭐⭐⭐
懒汉式(无同步)-不推荐
懒汉式 + 同步方法不推荐
双重检查锁否(有BUG)不推荐
双重检查锁 + volatile⭐⭐⭐⭐
静态内部类⭐⭐⭐⭐
枚举⭐⭐⭐⭐⭐

实际开发中,优先推荐使用 枚举方式(若允许非懒加载)或 静态内部类(需懒加载时)。若需更精细的控制,可选择 双重检查锁 + volatile

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。