单例模式详解(Java实现)

单例模式确保一个类只有一个实例,并提供全局访问点。核心原理:

  1. 私有化构造方法(禁止外部创建实例)
  2. 静态私有成员(持有唯一实例)
  3. 静态公有方法(提供全局访问入口)

一、实现方式对比

实现方式 线程安全 懒加载 防反射/序列化 代码复杂度 推荐指数
饿汉式 ★★☆☆☆
懒汉式(同步方法) ⭐⭐ ★★☆☆☆
双重检查锁(DCL) ⭐⭐⭐ ★★★☆☆
静态内部类 ⭐⭐ ★★★★☆
枚举 ★★★★★

二、具体实现及原理

1. 饿汉式(Eager Initialization)
java 复制代码
public class EagerSingleton {
    // 类加载时立即初始化(线程安全由JVM保证)
    private static final EagerSingleton INSTANCE = new EagerSingleton();
    
    private EagerSingleton() {} // 私有构造
    
    public static EagerSingleton getInstance() {
        return INSTANCE;
    }
}
  • 优点:实现简单,线程安全
  • 缺点:非懒加载,可能造成资源浪费
2. 懒汉式(Lazy Initialization - 同步方法)
java 复制代码
public class LazySingleton {
    private static LazySingleton instance;
    
    private LazySingleton() {}
    
    // 方法同步保证线程安全(性能瓶颈)
    public static synchronized LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}
  • 优点:懒加载
  • 缺点:同步方法性能差(每次调用都加锁)
3. 双重检查锁(Double-Checked Locking)
java 复制代码
public class DCLSingleton {
    // volatile禁止指令重排序(防止返回未初始化的对象)
    private volatile static DCLSingleton instance;
    
    private DCLSingleton() {}
    
    public static DCLSingleton getInstance() {
        if (instance == null) { // 第一次检查(避免不必要的锁)
            synchronized (DCLSingleton.class) {
                if (instance == null) { // 第二次检查(确保唯一性)
                    instance = new DCLSingleton();
                }
            }
        }
        return instance;
    }
}
  • 关键点volatile + 两次判空 + 同步块
  • 解决隐患:避免因指令重排序导致返回未初始化的对象
4. 静态内部类(Holder)
java 复制代码
public class HolderSingleton {
    private HolderSingleton() {}
    
    // 静态内部类在首次使用时加载
    private static class Holder {
        static final HolderSingleton INSTANCE = new HolderSingleton();
    }
    
    public static HolderSingleton getInstance() {
        return Holder.INSTANCE; // 触发类加载(线程安全由JVM保证)
    }
}
  • 原理 :利用JVM类加载机制(静态内部类在调用getInstance()时才加载)
  • 优势:天然线程安全 + 懒加载 + 无锁高性能
5. 枚举(Enum - 最佳实践)
java 复制代码
public enum EnumSingleton {
    INSTANCE; // 单例实例
    
    // 示例方法
    public void doSomething() {
        System.out.println("Singleton working");
    }
}
  • 使用方式EnumSingleton.INSTANCE.doSomething();
  • 优势
    • 绝对单例(JVM保证)
    • 自动防反射攻击
    • 自动防序列化破坏
    • 代码最简洁

三、常见问题解决方案

1. 反射攻击防护
java 复制代码
private Singleton() {
    // 防止通过反射创建新实例
    if (instance != null) {
        throw new IllegalStateException("Singleton already initialized");
    }
}

(枚举天然防御反射,无需额外处理)

2. 序列化破坏防护
java 复制代码
// 在非枚举实现中添加此方法
protected Object readResolve() {
    return getInstance(); // 反序列化时返回现有实例
}

四、总结建议

  • 首选枚举:满足所有单例需求(安全、简洁、防破坏)
  • 需要懒加载时:用静态内部类
  • 旧版本JDK(<1.5):用双重检查锁 (需确保volatile正确使用)
  • 避免饿汉式和同步方法懒汉式(存在明显缺陷)
相关推荐
fly-phantomWing1 天前
Maven的安装与配置的详细步骤
java·后端·maven·intellij-idea
2401_841495641 天前
【数据结构】红黑树的基本操作
java·数据结构·c++·python·算法·红黑树·二叉搜索树
学编程的小鬼1 天前
SpringBoot 自动装配原理剖析
java·spring boot·后端
@@神农1 天前
maven的概述以及在mac安装配置
java·macos·maven
杜子不疼.1 天前
【C++】玩转模板:进阶之路
java·开发语言·c++
夜晚中的人海1 天前
【C++】异常介绍
android·java·c++
Le1Yu1 天前
2025-9-28学习笔记
java·笔记·学习
C++chaofan1 天前
项目中为AI添加对话记忆
java·数据结构·人工智能·redis·缓存·个人开发·caffeine
老华带你飞1 天前
机电公司管理小程序|基于微信小程序的机电公司管理小程序设计与实现(源码+数据库+文档)
java·数据库·vue.js·spring boot·微信小程序·小程序·机电公司管理小程序
拾忆,想起1 天前
AMQP协议深度解析:消息队列背后的通信魔法
java·开发语言·spring boot·后端·spring cloud