java 什么是单例模式?如何实现单例模式?
单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类,并提供一个。
·
单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点。
单例模式的核心特点
- 唯一实例:类只能创建一个对象实例
- 全局访问:提供统一的访问入口
- 自行实例化:类自己负责创建自己的实例
- 严格控制:防止外部通过new创建实例
单例模式的实现方式
1. 饿汉式(线程安全)
public class Singleton {
// 类加载时就初始化(浪费内存)
private static final Singleton INSTANCE = new Singleton();
// 私有构造方法
private Singleton() {}
// 全局访问点
public static Singleton getInstance() {
return INSTANCE;
}
}
优点:实现简单,线程安全
缺点:类加载时就创建实例,可能造成资源浪费
2. 懒汉式(基础版,线程不安全)
public class Singleton {
private static Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton(); // 多线程下可能创建多个实例
}
return instance;
}
}
缺点:多线程环境下不安全
3. 懒汉式(同步方法,线程安全但效率低)
public class Singleton {
private static Singleton instance;
private Singleton() {}
// 方法同步,影响性能
public static synchronized Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
优点:线程安全
缺点:每次获取实例都要同步,性能差
4. 双重检查锁(DCL,推荐)
public class Singleton {
// volatile保证可见性和有序性
private static volatile Singleton instance;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) { // 第一次检查
synchronized (Singleton.class) {
if (instance == null) { // 第二次检查
instance = new Singleton();
}
}
}
return instance;
}
}
优点:线程安全,延迟加载,效率较高
注意:必须使用volatile防止指令重排序
5. 静态内部类(推荐)
public class Singleton {
private Singleton() {}
private static class Holder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return Holder.INSTANCE; // 首次调用时加载Holder类
}
}
优点:
- 线程安全(JVM类加载机制保证)
- 延迟加载(调用getInstance时才初始化)
- 实现简洁
6. 枚举式(最佳实践,推荐)
public enum Singleton {
INSTANCE; // 枚举实例本身就是单例
// 可以添加方法
public void doSomething() {
System.out.println("执行操作");
}
}
优点:
- 绝对防止多实例(JVM保证)
- 防止反射攻击
- 自动支持序列化
- 代码最简洁
单例模式的应用场景
- 配置管理:全局配置对象
- 日志系统:日志记录器
- 数据库连接池
- 线程池
- 缓存系统
- 设备驱动(如打印机)
- 状态管理(如游戏中的记分牌)
如何破坏单例及防御措施
1. 反射攻击
攻击方式:
Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
constructor.setAccessible(true);
Singleton newInstance = constructor.newInstance();
防御方法:
private Singleton() {
if (INSTANCE != null) {
throw new RuntimeException("禁止反射创建实例");
}
}
2. 序列化/反序列化
攻击方式:
// 序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton.ser"));
oos.writeObject(Singleton.getInstance());
// 反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("singleton.ser"));
Singleton newInstance = (Singleton) ois.readObject();
防御方法:
// 添加readResolve方法
private Object readResolve() {
return getInstance();
}
3. 克隆攻击
防御方法:
@Override
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
单例模式最佳实践
- 优先选择枚举实现:简单、安全、功能完备
- 考虑序列化需求:如需序列化,实现
readResolve方法 - 明确生命周期:考虑单例对象的创建和销毁时机
- 避免全局状态:单例可能成为"上帝对象",导致代码耦合
- 单元测试友好:设计时应考虑可测试性
代码示例(枚举实现)
public enum DatabaseConnection {
INSTANCE;
private Connection connection;
DatabaseConnection() {
try {
// 初始化数据库连接
String url = "jdbc:mysql://localhost:3306/mydb";
this.connection = DriverManager.getConnection(url, "user", "password");
} catch (SQLException e) {
throw new RuntimeException("数据库连接失败", e);
}
}
public Connection getConnection() {
return connection;
}
// 使用示例
public static void main(String[] args) {
Connection conn = DatabaseConnection.INSTANCE.getConnection();
// 使用连接...
}
}
单例模式是设计模式中最简单但最常用的模式之一,正确实现需要考虑线程安全、反射防御、序列化等问题。根据具体场景选择合适的实现方式,枚举方式在大多数情况下是最佳选择。
魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。
更多推荐

所有评论(0)