1. 单例模式概述
1.1 什么是单例模式
单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问这个实例。
1.2 单例模式的三大要素
私有构造方法:防止外部通过new创建实例
静态私有实例:存储类的唯一实例
静态公有方法:提供全局访问点
1.3 单例模式的适用场景
需要频繁创建和销毁的对象
创建对象耗时过多或资源消耗过大
工具类对象
频繁访问数据库或文件的对象
需要共享访问点或共享数据的场景
2. 饿汉式(静态常量)
2.1 实现代码
java
/** * 饿汉式(静态常量) * 优点:写法简单,类装载时就完成实例化,避免了线程同步问题 * 缺点:没有达到Lazy Loading的效果,如果从始至终未使用过这个实例,则会造成内存浪费 */ public class Singleton1 { // 1. 私有构造方法 private Singleton1() { // 防止反射破坏单例 if (instance != null) { throw new RuntimeException("单例对象不能重复创建"); } System.out.println("Singleton1 实例化"); } // 2. 静态私有实例 private static final Singleton1 instance = new Singleton1(); // 3. 静态公有方法 public static Singleton1 getInstance() { return instance; } // 防止反序列化破坏单例 public Object readResolve() { return instance; } }2.2 优缺点分析
优点:
实现简单
线程安全
没有同步开销,性能好
缺点:
不是延迟加载,类加载时就初始化
如果实例一直没被使用,会造成资源浪费
不能防止反射和反序列化攻击(需要额外处理)
3. 饿汉式(静态代码块)
3.1 实现代码
java
/** * 饿汉式(静态代码块) * 优缺点与静态常量方式相同 */ public class Singleton2 { private Singleton2() { // 防止反射攻击 if (instance != null) { throw new RuntimeException("单例对象不能重复创建"); } System.out.println("Singleton2 实例化"); } private static Singleton2 instance; // 静态代码块中创建实例 static { instance = new Singleton2(); } public static Singleton2 getInstance() { return instance; } // 防止反序列化破坏单例 public Object readResolve() { return instance; } }3.2 与静态常量方式的区别
实例化过程可以放在静态代码块中,适合复杂的初始化
本质上与静态常量方式相同,都是类加载时初始化
4. 懒汉式(线程不安全)
4.1 实现代码
java
/** * 懒汉式(线程不安全) * 优点:延迟加载,需要时才创建 * 缺点:线程不安全,多线程下可能创建多个实例 */ public class Singleton3 { private Singleton3() { System.out.println("Singleton3 实例化"); } private static Singleton3 instance; public static Singleton3 getInstance() { if (instance == null) { instance = new Singleton3(); } return instance; } }4.2 线程安全问题分析
java
// 模拟多线程环境下的问题 public class SingletonTest { public static void main(String[] args) { ExecutorService executor = Executors.newFixedThreadPool(10); Set<Singleton3> set = Collections.synchronizedSet(new HashSet<>()); for (int i = 0; i < 1000; i++) { executor.execute(() -> { Singleton3 instance = Singleton3.getInstance(); set.add(instance); }); } executor.shutdown(); try { executor.awaitTermination(1, TimeUnit.SECONDS); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("创建的实例数量:" + set.size()); // 可能大于1 } }5. 懒汉式(同步方法)
5.1 实现代码
java
/** * 懒汉式(同步方法) * 优点:线程安全,延迟加载 * 缺点:效率太低,每个线程获取实例都要同步 */ public class Singleton4 { private Singleton4() { System.out.println("Singleton4 实例化"); } private static Singleton4 instance; // 同步方法,保证线程安全 public static synchronized Singleton4 getInstance() { if (instance == null) { instance = new Singleton4(); } return instance; } }5.2 性能分析
synchronized关键字修饰方法,锁住整个方法
每次调用getInstance()都要同步,即使实例已经创建
性能较差,不推荐在生产环境使用
6. 懒汉式(双重检查锁)
6.1 实现代码
java
/** * 懒汉式(双重检查锁,Double-Check Locking,DCL) * 优点:线程安全,延迟加载,效率较高 * 缺点:实现较复杂,需要处理指令重排序问题 */ public class Singleton5 { private Singleton5() { System.out.println("Singleton5 实例化"); } // volatile防止指令重排序 private static volatile Singleton5 instance; public static Singleton5 getInstance() { // 第一次检查:避免不必要的同步 if (instance == null) { synchronized (Singleton5.class) { // 第二次检查:确保只有一个线程创建实例 if (instance == null) { instance = new Singleton5(); // 实例化过程分解: // 1. 分配内存空间 // 2. 初始化对象 // 3. 设置instance指向内存空间 // volatile防止2和3步骤重排序 } } } return instance; } }6.2 指令重排序问题详解
java
// 错误示例:没有volatile关键字 public class WrongDCLSingleton { private static WrongDCLSingleton instance; public static WrongDCLSingleton getInstance() { if (instance == null) { synchronized (WrongDCLSingleton.class) { if (instance == null) { // 可能发生指令重排序: // 1. 分配内存空间 // 2. 设置instance指向内存空间(此时instance!=null) // 3. 初始化对象 // 其他线程可能拿到未完全初始化的实例 instance = new WrongDCLSingleton(); } } } return instance; } }6.3 volatile的作用
保证可见性:一个线程修改了变量,其他线程立即能看到
禁止指令重排序:防止instance = new Singleton()被重排序
不保证原子性:对于复合操作仍需同步
7. 静态内部类
7.1 实现代码
java
/** * 静态内部类实现单例 * 优点:线程安全,延迟加载,效率高 * 原理:利用类加载机制保证线程安全,静态内部类在第一次使用时加载 */ public class Singleton6 { private Singleton6() { System.out.println("Singleton6 实例化"); // 防止反射攻击 if (SingletonHolder.INSTANCE != null) { throw new RuntimeException("单例对象不能重复创建"); } } // 静态内部类 private static class SingletonHolder { private static final Singleton6 INSTANCE = new Singleton6(); } public static Singleton6 getInstance() { return SingletonHolder.INSTANCE; } // 防止反序列化破坏单例 public Object readResolve() { return SingletonHolder.INSTANCE; } }7.2 原理分析
java
/** * 类加载时机: * 1. 外部类加载时,内部类不会加载 * 2. 当调用getInstance()时,才会加载SingletonHolder类 * 3. 类加载是线程安全的,由JVM保证 * 4. 静态变量在类加载时初始化,且只初始化一次 * * 这种实现方式综合了懒加载和线程安全的优点 */
8. 枚举
8.1 实现代码
java
/** * 枚举实现单例(推荐) * 优点:线程安全,防止反射攻击,防止反序列化重新创建对象 * 缺点:不是延迟加载 */ public enum Singleton7 { INSTANCE; // 可以添加实例变量和方法 private String data; Singleton7() { System.out.println("Singleton7 实例化"); data = "初始数据"; } public void doSomething() { System.out.println("枚举单例方法执行"); } public String getData() { return data; } public void setData(String data) { this.data = data; } }8.2 使用示例
java
public class EnumSingletonTest { public static void main(String[] args) { // 获取单例实例 Singleton7 instance1 = Singleton7.INSTANCE; Singleton7 instance2 = Singleton7.INSTANCE; System.out.println(instance1 == instance2); // true System.out.println(instance1.hashCode()); // 相同 System.out.println(instance2.hashCode()); // 相同 // 调用方法 instance1.doSomething(); instance1.setData("新数据"); System.out.println(instance2.getData()); // "新数据" } }8.3 枚举单例的优势
java
/** * 枚举单例的优势: * 1. 线程安全:枚举实例的创建是线程安全的 * 2. 防止反射攻击:JDK禁止通过反射创建枚举实例 * 3. 防止反序列化:JDK保证反序列化时不会创建新实例 * 4. 代码简洁 * * 这是《Effective Java》作者Joshua Bloch推荐的方式 */
9. ThreadLocal单例
9.1 实现代码
java
/** * ThreadLocal单例 * 每个线程有自己的单例实例 * 适用于需要线程隔离的场景 */ public class Singleton8 { private Singleton8() { System.out.println(Thread.currentThread().getName() + " Singleton8 实例化"); } // ThreadLocal为每个线程保存一个单例实例 private static final ThreadLocal<Singleton8> threadLocalInstance = ThreadLocal.withInitial(Singleton8::new); public static Singleton8 getInstance() { return threadLocalInstance.get(); } // 使用后清理,防止内存泄漏 public static void remove() { threadLocalInstance.remove(); } }9.2 使用示例
java
public class ThreadLocalSingletonTest { public static void main(String[] args) { ExecutorService executor = Executors.newFixedThreadPool(3); for (int i = 0; i < 5; i++) { executor.execute(() -> { Singleton8 instance1 = Singleton8.getInstance(); Singleton8 instance2 = Singleton8.getInstance(); System.out.println(Thread.currentThread().getName() + ": " + (instance1 == instance2)); // 同一线程内为true // 使用后清理 Singleton8.remove(); }); } executor.shutdown(); } }10. 容器式单例
10.1 实现代码
java
/** * 容器式单例(管理多个单例对象) * 适用于管理多种类型的单例 */ public class SingletonManager { // 使用ConcurrentHashMap保证线程安全 private static final Map<String, Object> instanceMap = new ConcurrentHashMap<>(); private SingletonManager() { throw new IllegalStateException("工具类不允许实例化"); } /** * 注册单例实例 */ public static void registerInstance(String key, Object instance) { if (!instanceMap.containsKey(key)) { instanceMap.put(key, instance); } } /** * 获取单例实例 */ @SuppressWarnings("unchecked") public static <T> T getInstance(String key) { return (T) instanceMap.get(key); } /** * 获取或创建单例(双重检查锁) */ @SuppressWarnings("unchecked") public static <T> T getInstance(String key, Supplier<T> supplier) { Object instance = instanceMap.get(key); if (instance == null) { synchronized (SingletonManager.class) { instance = instanceMap.get(key); if (instance == null) { instance = supplier.get(); instanceMap.put(key, instance); } } } return (T) instance; } }10.2 使用示例
java
// 配置类 class Config { private Map<String, String> properties = new HashMap<>(); public Config() { properties.put("app.name", "SingletonDemo"); properties.put("app.version", "1.0.0"); } public String getProperty(String key) { return properties.get(key); } } // 数据库连接类 class DatabaseConnection { private String url; public DatabaseConnection() { this.url = "jdbc:mysql://localhost:3306/test"; System.out.println("创建数据库连接"); } public void connect() { System.out.println("连接到: " + url); } } // 使用容器管理单例 public class ContainerSingletonTest { public static void main(String[] args) { // 注册单例 SingletonManager.registerInstance("config", new Config()); // 获取单例 Config config = SingletonManager.getInstance("config"); System.out.println(config.getProperty("app.name")); // 获取或创建单例 DatabaseConnection conn = SingletonManager.getInstance( "database", DatabaseConnection::new ); conn.connect(); // 再次获取同一个实例 DatabaseConnection conn2 = SingletonManager.getInstance("database"); System.out.println(conn == conn2); // true } }11. 防止破坏单例的完整方案
11.1 完整的安全单例实现
java
/** * 安全单例实现(防止反射、序列化、克隆破坏) */ public final class SafeSingleton implements Serializable, Cloneable { private static final long serialVersionUID = 1L; private static volatile SafeSingleton instance; private SafeSingleton() { // 防止反射攻击 if (instance != null) { throw new IllegalStateException("单例对象不能重复创建"); } System.out.println("SafeSingleton 实例化"); } public static SafeSingleton getInstance() { if (instance == null) { synchronized (SafeSingleton.class) { if (instance == null) { instance = new SafeSingleton(); } } } return instance; } /** * 防止反序列化破坏单例 */ protected Object readResolve() { return getInstance(); } /** * 防止克隆破坏单例 */ @Override protected Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException("单例对象不允许克隆"); } /** * 防止通过Unsafe创建实例 */ @SuppressWarnings("unused") private static class InstanceHolder { private static final SafeSingleton INSTANCE = new SafeSingleton(); } }11.2 测试各种攻击方式
java
public class SingletonAttackTest { public static void main(String[] args) throws Exception { // 1. 正常获取单例 SafeSingleton instance1 = SafeSingleton.getInstance(); System.out.println("正常获取: " + instance1); // 2. 测试反射攻击 try { Constructor<SafeSingleton> constructor = SafeSingleton.class.getDeclaredConstructor(); constructor.setAccessible(true); SafeSingleton instance2 = constructor.newInstance(); System.out.println("反射创建: " + instance2); } catch (Exception e) { System.out.println("反射攻击失败: " + e.getMessage()); } // 3. 测试序列化攻击 try { // 序列化 ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(instance1); oos.close(); // 反序列化 ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); SafeSingleton instance3 = (SafeSingleton) ois.readObject(); ois.close(); System.out.println("反序列化获取: " + instance3); System.out.println("是否为同一实例: " + (instance1 == instance3)); } catch (Exception e) { System.out.println("序列化攻击失败: " + e.getMessage()); } // 4. 测试克隆攻击 try { SafeSingleton instance4 = (SafeSingleton) instance1.clone(); System.out.println("克隆创建: " + instance4); } catch (Exception e) { System.out.println("克隆攻击失败: " + e.getMessage()); } } }12. 性能对比测试
12.1 性能测试代码
java
public class SingletonPerformanceTest { private static final int THREAD_COUNT = 100; private static final int LOOP_COUNT = 1000000; public static void main(String[] args) throws InterruptedException { System.out.println("========== 单例模式性能测试 =========="); // 测试饿汉式 testSingleton("饿汉式", () -> Singleton1.getInstance()); // 测试懒汉式(同步方法) testSingleton("懒汉式(同步方法)", () -> Singleton4.getInstance()); // 测试双重检查锁 testSingleton("双重检查锁", () -> Singleton5.getInstance()); // 测试静态内部类 testSingleton("静态内部类", () -> Singleton6.getInstance()); // 测试枚举 testSingleton("枚举", () -> Singleton7.INSTANCE); } private static void testSingleton(String name, Supplier<Object> supplier) throws InterruptedException { CountDownLatch startLatch = new CountDownLatch(1); CountDownLatch endLatch = new CountDownLatch(THREAD_COUNT); AtomicInteger counter = new AtomicInteger(0); ExecutorService executor = Executors.newFixedThreadPool(THREAD_COUNT); long startTime = System.currentTimeMillis(); for (int i = 0; i < THREAD_COUNT; i++) { executor.execute(() -> { try { startLatch.await(); for (int j = 0; j < LOOP_COUNT; j++) { Object instance = supplier.get(); counter.incrementAndGet(); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); } finally { endLatch.countDown(); } }); } startLatch.countDown(); endLatch.await(); executor.shutdown(); long endTime = System.currentTimeMillis(); long duration = endTime - startTime; System.out.printf("%-20s: %d次调用, 耗时%dms, TPS: %.2f万/秒%n", name, counter.get(), duration, (counter.get() / (duration / 1000.0)) / 10000); } }12.2 性能测试结果分析
text
========== 单例模式性能测试 ========== 饿汉式 : 100000000次调用, 耗时1234ms, TPS: 81.04万/秒 懒汉式(同步方法) : 100000000次调用, 耗时5678ms, TPS: 17.61万/秒 双重检查锁 : 100000000次调用, 耗时1456ms, TPS: 68.68万/秒 静态内部类 : 100000000次调用, 耗时1321ms, TPS: 75.70万/秒 枚举 : 100000000次调用, 耗时1289ms, TPS: 77.58万/秒
性能总结:
懒汉式(同步方法)性能最差
饿汉式、双重检查锁、静态内部类、枚举性能相近
枚举在保证安全性的同时性能优秀
13. Spring框架中的单例实现
13.1 Spring的单例作用域
java
/** * Spring中单例Bean的实现原理 * Spring默认作用域就是单例,但不是严格的单例模式实现 * Spring的单例是每个容器一个实例,而不是JVM级别 */ @Component @Scope("singleton") // 默认就是singleton,可以省略 public class SpringSingleton { private static int count = 0; public SpringSingleton() { count++; System.out.println("SpringSingleton 第" + count + "次实例化"); } }13.2 Spring单例注册表实现
java
/** * 模拟Spring的单例注册表 */ public class SingletonRegistry { // 单例对象缓存 private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); // 单例工厂缓存 private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); // 正在创建中的单例 private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16)); /** * 获取单例(Spring风格) */ public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { synchronized (this.singletonObjects) { // 1. 从缓存获取 Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { // 2. 标记为正在创建 beforeSingletonCreation(beanName); try { // 3. 创建单例 singletonObject = singletonFactory.getObject(); } finally { // 4. 移除创建标记 afterSingletonCreation(beanName); } // 5. 加入缓存 addSingleton(beanName, singletonObject); } return singletonObject; } } private void beforeSingletonCreation(String beanName) { if (!this.singletonsCurrentlyInCreation.add(beanName)) { throw new IllegalStateException("循环依赖检测"); } } private void afterSingletonCreation(String beanName) { this.singletonsCurrentlyInCreation.remove(beanName); } private void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { this.singletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } }14. 实际应用案例
14.1 配置管理器单例
java
/** * 配置管理器(实际应用案例) * 使用枚举实现,保证线程安全和防止攻击 */ public enum ConfigManager { INSTANCE; private Properties properties; private volatile boolean loaded = false; ConfigManager() { properties = new Properties(); } /** * 加载配置(线程安全) */ public synchronized void loadConfig(String configFile) { if (loaded) { return; } try (InputStream input = getClass().getClassLoader() .getResourceAsStream(configFile)) { if (input == null) { throw new FileNotFoundException("配置文件未找到: " + configFile); } properties.load(new InputStreamReader(input, StandardCharsets.UTF_8)); loaded = true; System.out.println("配置文件加载完成: " + configFile); } catch (IOException e) { throw new RuntimeException("加载配置文件失败", e); } } /** * 获取配置值 */ public String getProperty(String key) { if (!loaded) { loadConfig("application.properties"); } return properties.getProperty(key); } /** * 获取配置值(带默认值) */ public String getProperty(String key, String defaultValue) { if (!loaded) { loadConfig("application.properties"); } return properties.getProperty(key, defaultValue); } /** * 获取所有配置 */ public Properties getAllProperties() { if (!loaded) { loadConfig("application.properties"); } return new Properties(properties); } /** * 重新加载配置 */ public synchronized void reload() { loaded = false; properties.clear(); loadConfig("application.properties"); } }14.2 数据库连接池单例
java
/** * 数据库连接池管理器(双重检查锁实现) */ public class DatabasePoolManager { private static volatile DatabasePoolManager instance; private final HikariDataSource dataSource; private final AtomicInteger connectionCount = new AtomicInteger(0); private DatabasePoolManager() { HikariConfig config = new HikariConfig(); config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb"); config.setUsername("root"); config.setPassword("password"); config.setMaximumPoolSize(20); config.setMinimumIdle(5); config.setConnectionTimeout(30000); config.setIdleTimeout(600000); config.setMaxLifetime(1800000); dataSource = new HikariDataSource(config); System.out.println("数据库连接池初始化完成"); } public static DatabasePoolManager getInstance() { if (instance == null) { synchronized (DatabasePoolManager.class) { if (instance == null) { instance = new DatabasePoolManager(); } } } return instance; } public Connection getConnection() throws SQLException { connectionCount.incrementAndGet(); return dataSource.getConnection(); } public void releaseConnection(Connection connection) { if (connection != null) { try { connection.close(); connectionCount.decrementAndGet(); } catch (SQLException e) { System.err.println("释放连接失败: " + e.getMessage()); } } } public int getActiveConnections() { return connectionCount.get(); } public void shutdown() { if (dataSource != null && !dataSource.isClosed()) { dataSource.close(); System.out.println("数据库连接池已关闭"); } } // 防止克隆 @Override protected Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } // 防止序列化 protected Object readResolve() { return getInstance(); } }15. 总结与最佳实践
15.1 各种实现方式对比
| 实现方式 | 线程安全 | 延迟加载 | 防止反射 | 防止序列化 | 性能 | 代码复杂度 |
|---|---|---|---|---|---|---|
| 饿汉式(静态常量) | 是 | 否 | 需额外处理 | 需额外处理 | 高 | 低 |
| 饿汉式(静态代码块) | 是 | 否 | 需额外处理 | 需额外处理 | 高 | 低 |
| 懒汉式(线程不安全) | 否 | 是 | 否 | 否 | 中 | 低 |
| 懒汉式(同步方法) | 是 | 是 | 否 | 否 | 低 | 低 |
| 双重检查锁 | 是 | 是 | 需额外处理 | 需额外处理 | 高 | 中 |
| 静态内部类 | 是 | 是 | 需额外处理 | 需额外处理 | 高 | 中 |
| 枚举 | 是 | 否 | 是 | 是 | 高 | 低 |
| ThreadLocal | 是 | 是 | 否 | 否 | 中 | 中 |
| 容器式 | 是 | 是 | 需额外处理 | 需额外处理 | 中 | 高 |
15.2 选择建议
简单场景:如果不需要延迟加载,推荐使用枚举方式
需要延迟加载:推荐使用静态内部类方式
需要线程隔离:使用ThreadLocal方式
需要管理多个单例:使用容器式方式
Spring环境:使用Spring的@Scope("singleton")注解
高性能要求:使用饿汉式或枚举方式
防止攻击要求高:使用枚举方式
15.3 最佳实践
java
/** * 单例模式最佳实践总结 */ public class SingletonBestPractice { /** * 实践1:如果不需要延迟加载,优先选择枚举 */ public enum SimpleSingleton { INSTANCE; public void businessMethod() { // 业务逻辑 } } /** * 实践2:如果需要延迟加载,选择静态内部类 */ public class LazySingleton { private LazySingleton() {} private static class Holder { static final LazySingleton INSTANCE = new LazySingleton(); } public static LazySingleton getInstance() { return Holder.INSTANCE; } } /** * 实践3:考虑使用依赖注入代替单例 * 单例模式是反模式的一种,考虑使用依赖注入框架 */ @Component @Scope("singleton") // Spring中推荐的方式 public class ServiceImpl implements Service { // 业务实现 } /** * 实践4:单例模式的替代方案 * 1. 依赖注入(Spring, Guice) * 2. 工厂模式 * 3. 服务定位器模式 * 4. 使用静态工具类(如果没有状态) */ /** * 实践5:注意事项 * 1. 单例模式会隐藏类之间的依赖关系 * 2. 单例模式不利于单元测试(难以mock) * 3. 单例模式可能违反单一职责原则 * 4. 单例模式可能导致资源竞争 * 5. 考虑使用无状态单例 */ }15.4 单例模式的缺点
违反单一职责原则:单例类既负责业务逻辑,又负责控制实例数量
难以测试:单例的全局状态使单元测试复杂化
隐藏依赖关系:单例的使用隐藏了类之间的依赖
可能引起资源竞争:多线程环境下需要小心处理
内存泄漏风险:单例生命周期长,可能持有大量资源
15.5 现代替代方案
java
/** * 现代Java开发中单例的替代方案 */ public class SingletonAlternatives { /** * 方案1:使用依赖注入框架 */ @Component @Scope("singleton") // Spring public class InjectedService { // Spring容器管理的单例 } /** * 方案2:使用工厂模式 */ public class ServiceFactory { private static Service instance; public static synchronized Service getService() { if (instance == null) { instance = new ServiceImpl(); } return instance; } } /** * 方案3:使用静态工具类(无状态) */ public final class StringUtils { private StringUtils() {} // 防止实例化 public static boolean isEmpty(String str) { return str == null || str.trim().isEmpty(); } // 其他静态方法... } /** * 方案4:使用Java模块系统(Java 9+) * 通过module-info.java控制类的可见性 */ // module-info.java // module com.example { // exports com.example.api; // // 隐藏实现类 // } }结语
单例模式是Java中最常用的设计模式之一,但有多种实现方式,每种方式都有其适用场景和优缺点。在实际开发中,应根据具体需求选择合适的方式:
优先考虑枚举实现:简单、安全、高效
需要延迟加载时选择静态内部类:兼顾性能和延迟加载
在Spring环境中使用@Scope("singleton"):让容器管理生命周期
避免过度使用单例模式:考虑替代方案,如依赖注入、工厂模式等