每日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开发者来说是非常重要的,它不仅能够帮助我们写出更好的代码,还能够在面试中展示我们的设计能力。

感谢读者观看!

相关推荐
okseekw2 小时前
递归:不止是 “自己调用自己”,看完这篇秒懂
java·后端
sg_knight2 小时前
什么是设计模式?为什么 Python 也需要设计模式
开发语言·python·设计模式
琢磨先生David2 小时前
Java算法题:移除数组中的重复项
java·数据结构·算法
Java天梯之路2 小时前
手撸 Spring 简易版 AOP
java·spring boot·面试
Java天梯之路2 小时前
Spring AOP 源码深度解析:从代理创建到通知执行的完整链路
java·spring boot·面试
小光学长2 小时前
基于web的影视网站设计与实现14yj533o(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
java·前端·数据库
何中应2 小时前
【面试题-2】Java集合
java·开发语言·后端·面试题
BullSmall2 小时前
Tomcat SSL 配置及常见问题
java·tomcat·ssl
璞瑜无文2 小时前
Unity 游戏开发之方块随机生成(三)
java·unity·游戏引擎