每日Java面试场景题知识点之-单例模式

每日Java面试场景题知识点之-单例模式

一、单例模式概述

单例模式(Singleton Pattern)是Java中最简单也是最常用的设计模式之一。它保证一个类只有一个实例,并提供一个全局访问点来访问这个实例。在Java企业级项目中,单例模式广泛应用于配置管理、数据库连接池、缓存管理等场景。

二、单例模式的多种实现方式

1. 饿汉式单例模式

java 复制代码
public class EagerSingleton {
    // 在类加载时就创建实例,线程安全但可能造成资源浪费
    private static final EagerSingleton instance = new EagerSingleton();
    
    private EagerSingleton() {}
    
    public static EagerSingleton getInstance() {
        return instance;
    }
}

特点:

  • 线程安全
  • 类加载时就创建实例
  • 可能造成资源浪费

2. 懒汉式单例模式(线程不安全)

java 复制代码
public class LazySingleton {
    private static LazySingleton instance;
    
    private LazySingleton() {}
    
    public static LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}

**问题:**在多线程环境下,可能创建多个实例。

3. 懒汉式单例模式(线程安全)

java 复制代码
public class ThreadSafeLazySingleton {
    private static ThreadSafeLazySingleton instance;
    
    private ThreadSafeLazySingleton() {}
    
    public static synchronized ThreadSafeLazySingleton getInstance() {
        if (instance == null) {
            instance = new ThreadSafeLazySingleton();
        }
        return instance;
    }
}

特点:

  • 线程安全
  • 性能较差(每次获取实例都要同步)

4. 双重检查锁定(DCL)

java 复制代码
public class DCLSingleton {
    private static volatile DCLSingleton instance;
    
    private DCLSingleton() {}
    
    public static DCLSingleton getInstance() {
        if (instance == null) {
            synchronized (DCLSingleton.class) {
                if (instance == null) {
                    instance = new DCLSingleton();
                }
            }
        }
        return instance;
    }
}

特点:

  • 线程安全
  • 性能较好
  • 需要使用volatile关键字防止指令重排序

5. 静态内部类方式

java 复制代码
public class InnerClassSingleton {
    private InnerClassSingleton() {}
    
    private static class SingletonHolder {
        private static final InnerClassSingleton INSTANCE = new InnerClassSingleton();
    }
    
    public static InnerClassSingleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

特点:

  • 线程安全
  • 延迟加载
  • 性能最好

6. 枚举方式

java 复制代码
public enum EnumSingleton {
    INSTANCE;
    
    public void doSomething() {
        // 业务逻辑
    }
}

特点:

  • 线程安全
  • 防止反射攻击
  • 防止序列化破坏

三、企业级项目中的实际应用场景

1. 配置管理器

在大型企业应用中,配置信息通常需要全局共享且只加载一次。

java 复制代码
public class ConfigManager {
    private static volatile ConfigManager instance;
    private Properties properties;
    
    private ConfigManager() {
        properties = new Properties();
        loadConfig();
    }
    
    public static ConfigManager getInstance() {
        if (instance == null) {
            synchronized (ConfigManager.class) {
                if (instance == null) {
                    instance = new ConfigManager();
                }
            }
        }
        return instance;
    }
    
    private void loadConfig() {
        try {
            properties.load(ConfigManager.class.getClassLoader().getResourceAsStream("config.properties"));
        } catch (IOException e) {
            throw new RuntimeException("加载配置文件失败", e);
        }
    }
    
    public String getProperty(String key) {
        return properties.getProperty(key);
    }
}

2. 数据库连接池

数据库连接池是单例模式的典型应用,确保全局只有一个连接池实例。

java 复制代码
public class ConnectionPool {
    private static volatile ConnectionPool instance;
    private DataSource dataSource;
    
    private ConnectionPool() {
        initDataSource();
    }
    
    public static ConnectionPool getInstance() {
        if (instance == null) {
            synchronized (ConnectionPool.class) {
                if (instance == null) {
                    instance = new ConnectionPool();
                }
            }
        }
        return instance;
    }
    
    private void initDataSource() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
        config.setUsername("root");
        config.setPassword("password");
        config.setMaximumPoolSize(20);
        
        dataSource = new HikariDataSource(config);
    }
    
    public Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }
}

3. 缓存管理器

在电商系统中,缓存管理器通常需要全局唯一实例。

java 复制代码
public class CacheManager {
    private static volatile CacheManager instance;
    private Cache<String, Object> cache;
    
    private CacheManager() {
        cache = Caffeine.newBuilder()
            .maximumSize(1000)
            .expireAfterWrite(10, TimeUnit.MINUTES)
            .build();
    }
    
    public static CacheManager getInstance() {
        if (instance == null) {
            synchronized (CacheManager.class) {
                if (instance == null) {
                    instance = new CacheManager();
                }
            }
        }
        return instance;
    }
    
    public void put(String key, Object value) {
        cache.put(key, value);
    }
    
    public Object get(String key) {
        return cache.getIfPresent(key);
    }
    
    public void remove(String key) {
        cache.invalidate(key);
    }
}

四、常见问题及解决方案

1. 线程安全问题

**问题:**在多线程环境下,单例模式可能创建多个实例。

解决方案:

  • 使用synchronized关键字
  • 使用双重检查锁定(DCL)
  • 使用静态内部类
  • 使用枚举

2. 反射攻击问题

**问题:**通过反射可以破坏单例模式。

解决方案:

java 复制代码
private Singleton() {
    if (instance != null) {
        throw new RuntimeException("单例模式不允许反射创建实例");
    }
}

3. 序列化破坏问题

**问题:**通过序列化和反序列化可以破坏单例模式。

解决方案:

java 复制代码
protected Object readResolve() {
    return getInstance();
}

4. 性能问题

**问题:**同步方法会影响性能。

解决方案:

  • 使用双重检查锁定
  • 使用静态内部类
  • 使用枚举

五、最佳实践

  1. 选择合适的实现方式:根据具体场景选择最适合的单例实现方式
  2. 考虑线程安全:在多线程环境中必须保证线程安全
  3. 防止反射和序列化破坏:对于重要的单例类,需要防止反射和序列化破坏
  4. 考虑资源管理:确保单例类能够正确管理资源
  5. 避免过度使用:单例模式虽然方便,但过度使用会导致代码耦合度高

六、总结

单例模式是Java企业级开发中的重要设计模式,它保证一个类只有一个实例,并提供全局访问点。在实际项目中,我们需要根据具体场景选择合适的实现方式,并注意线程安全、反射攻击、序列化破坏等问题。

掌握单例模式对于Java开发者来说是非常重要的,它不仅能够帮助我们写出更好的代码,还能够在面试中展示我们的设计能力。

感谢读者观看!

相关推荐
wuminyu4 小时前
专家视角看Java字节码加载与存储指令机制
java·linux·c语言·jvm·c++
callJJ5 小时前
Spring Data Redis 两种编程模型详解:同步 vs 响应式
java·spring boot·redis·python·spring
kyriewen5 小时前
代码写成一锅粥?3个设计模式让你的项目“起死回生”
前端·javascript·设计模式
千寻girling6 小时前
《 Git 详细教程 》
前端·后端·面试
wbs_scy6 小时前
Linux线程同步与互斥(三):线程同步深度解析之POSIX 信号量与环形队列生产者消费者模型,从原理到源码彻底吃透
java·开发语言
jinanwuhuaguo7 小时前
(第三十三篇)五月的文明奠基:OpenClaw 2026.5.2版本的文明级解读
android·java·开发语言·人工智能·github·拓扑学·openclaw
xmjd msup8 小时前
spring security 超详细使用教程(接入springboot、前后端分离)
java·spring boot·spring
Cosolar8 小时前
一文吃透 LangChain&LangGraph:设计理念、框架结构与内部组件全拆解
人工智能·面试·架构
952368 小时前
SpringBoot统一功能处理
java·spring boot·后端
Lyyaoo.8 小时前
优惠券秒杀业务分析
java·开发语言