当前位置: 首页 > news >正文

Java单例模式详解

单例模式详解

一、单例模式概述

单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问这个实例。

核心特点

  • 唯一实例:保证一个类只有一个实例存在
  • 全局访问:提供统一的访问入口
  • 延迟初始化:通常采用懒加载方式创建实例
  • 线程安全:需要考虑多线程环境下的安全性

二、单例模式的实现方式

1. 懒汉式(线程不安全)

public class Singleton {
    private static Singleton instance;
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

缺点:多线程环境下可能创建多个实例

2. 懒汉式(线程安全)

public class Singleton {
    private static Singleton instance;
    
    private Singleton() {}
    
    public static synchronized Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

缺点:每次获取实例都要同步,性能较差

3. 双重检查锁定(DCL)

public class Singleton {
    private volatile static Singleton instance;
    
    private Singleton() {}
    
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

特点

  • volatile关键字防止指令重排序
  • 第一次检查避免不必要的同步
  • 第二次检查确保只创建一个实例

4. 静态内部类实现

public class Singleton {
    private Singleton() {}
    
    private static class SingletonHolder {
        private static final Singleton INSTANCE = new Singleton();
    }
    
    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

优点

  • 线程安全
  • 延迟加载
  • 实现简单

5. 枚举实现(推荐)

public enum Singleton {
    INSTANCE;
    
    public void doSomething() {
        // 业务方法
    }
}

优势

  • 绝对防止多次实例化
  • 自动支持序列化机制
  • 线程安全
  • 代码简洁

三、单例模式的应用场景

1. 配置管理类

public class AppConfig {
    private static AppConfig instance;
    private Properties configs;
    
    private AppConfig() {
        // 初始化加载配置
        configs = new Properties();
        try (InputStream is = getClass().getResourceAsStream("/config.properties")) {
            configs.load(is);
        } catch (IOException e) {
            throw new RuntimeException("加载配置文件失败", e);
        }
    }
    
    public static synchronized AppConfig getInstance() {
        if (instance == null) {
            instance = new AppConfig();
        }
        return instance;
    }
    
    public String getConfig(String key) {
        return configs.getProperty(key);
    }
}

使用场景

  • 全局配置信息管理
  • 避免重复加载配置文件
  • 统一配置访问入口

2. 数据库连接池

public class ConnectionPool {
    private static ConnectionPool instance;
    private List<Connection> pool;
    
    private ConnectionPool() {
        // 初始化连接池
        pool = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            pool.add(createConnection());
        }
    }
    
    public static ConnectionPool getInstance() {
        if (instance == null) {
            synchronized (ConnectionPool.class) {
                if (instance == null) {
                    instance = new ConnectionPool();
                }
            }
        }
        return instance;
    }
    
    public Connection getConnection() {
        // 从池中获取连接
    }
    
    public void releaseConnection(Connection conn) {
        // 释放连接回池
    }
}

优势

  • 避免频繁创建连接开销
  • 统一管理数据库连接
  • 控制连接数量

四、单例模式的注意事项

  1. 序列化问题

    • 实现Serializable接口时需要添加readResolve()方法

    • 防止反序列化时创建新实例

      private Object readResolve() {
      return getInstance();
      }

  2. 反射攻击防护

    • 防止通过反射调用私有构造方法

    • 可以在构造方法中添加检查

      private Singleton() {
      if (instance != null) {
      throw new IllegalStateException(“单例实例已存在”);
      }
      }

五、总结

单例模式是最常用的设计模式之一,适用于需要全局唯一访问点的场景。在选择实现方式时:

  • Java 5+环境:优先使用枚举实现
  • 需要延迟加载:考虑静态内部类方式
  • 性能敏感场景:使用双重检查锁定
  • 简单场景:可以使用同步方法实现

正确使用单例模式可以:

  • 减少系统资源消耗
  • 提供一致的访问入口
  • 简化对象管理
  • 避免状态不一致问题
http://www.dtcms.com/a/108159.html

相关文章:

  • 深入理解 CSS 选择器:从基础到高级的样式控制
  • iPhone 16怎么录制屏幕内容?屏幕录制技巧、软件分享
  • eBest AI智能报表:用自然语言对话解锁企业数据生产力
  • PostgreSQL HAVING 子句详解
  • 最小二乘求解器lstsq,处理带权重和L2正则的线性回归
  • Vue3 + Element Plus + AntV X6 实现拖拽树组件
  • 【人工智能之大模型】如何缓解大语言模型LLMs重复读的问题?
  • 函数ioctl(Input/Output Control)
  • mac如何将jar包上传到maven中央仓库中
  • LeetCode-695. 岛屿的最大面积
  • Linux系统之systemctl管理服务及编译安装配置文件安装实现systemctl管理服务
  • Redis-10.在Java中操作Redis-Spring Data Redis使用方式-操作步骤说明
  • 基于随机森林算法的信用风险评估项目
  • 汇编学习结语
  • Dify案例-接入飞书云文档实现需求质量评估
  • MongoDB文档操作
  • 基于HTML5的音乐播放器(源码+lw+部署文档+讲解),源码可白嫖!
  • vscode代码片段的设置与使用
  • 填坑日志(20250402)解决Jira Rest API出现403XSRF check failed报错的问题
  • Ansible(4)—— Playbook
  • STL 性能优化实战:解决项目中标准模板库的性能瓶颈
  • C语言跳表(Skip List)算法:数据世界的“时光穿梭机”
  • Node.js v22.14.0 多平台安装指南:Windows、Linux 和 macOS 详细教程
  • 当AI开始“思考“:大语言模型的文字认知三部曲
  • Vue 中 this.$emit(“update:xx“,value) 和 :xx.sync 实现同步数据的做法
  • 创建灵活可配置的轮播图组件: GrapesJS 与 Vue3 的完美结合
  • 超短波通信模拟设备:增强通信能力的关键工具
  • 【3.软件工程】3.2 瀑布模型
  • MySQL 高级查询:JOIN、子查询、窗口函数
  • 3D AI 公司 VAST 开源基础 3D 生成模型 TripoSG 和 TripoSF