并发编程(二十三):单例模式(二):静态/非静态方法:单例内存优化关键

单例模式的核心是保证一个类全局仅有一个实例,而实际开发中,我们不仅要实现单例,更要兼顾内存优化、线程安全与扩展性。并发编程(二十二):单例模式总览篇:概念、分类与基础实现-CSDN博客

一、静态方法 vs 非静态方法

"静态方法不用创建对象,为什么不适合作为Servlet/Controller的业务方法?",原因在于内存占用逻辑与扩展性

1 类加载 vs 类初始化

1. 类加载(硬盘 → 内存)

  • 时机 :类首次被使用时(比如第一次调用类的方法、访问类的变量、new 对象),JVM 把硬盘上的 .class 文件加载到内存
  • 内容 :加载类的元信息(类名、方法名、变量名等),但不执行静态代码 / 初始化静态变量

2. 类初始化(内存里初始化)

  • 时机 :类加载后,首次使用类的静态成员(静态方法、静态变量、静态块)时触发
  • 内容 :执行静态块、初始化静态变量,静态成员一旦初始化就永久占内存,直到 JVM 退出

二、静态方法的问题:"不用也占内存"

1. 静态方法的内存逻辑

静态方法 ≠ 不用创建对象,但 类加载 + 初始化后就永久占内存

  • 静态方法属于类本身 ,不是对象,调用时不用 new 对象(比如 ServletUtil.doGet()
  • 只要这个类被加载到内存,静态方法的元信息 + 执行逻辑就永久占内存,哪怕你从没调用过这个静态方法
  • 这和枚举 / 饿汉式单例的问题完全一样:提前占内存,不符合 "按需使用" 的优化

2. 静态方法 vs 非静态方法(单例场景)

特性 静态方法 非静态方法(DCL 单例)
调用方式 类名.方法(不用对象) 对象.方法(需单例对象)
内存占用时机 类加载后就占内存(永久) 第一次调用方法时,创建单例对象才占内存
极限优化适配性 不适配(提前占内存) 适配(按需占内存)
灵活性 差(静态方法不能重写) 好(非静态方法可继承 / 重写)

Q: "为什么不用静态方法代替单例?静态方法不用创建对象啊"

A:

  1. 静态方法虽然不用创建对象,但类一加载,静态方法就占内存------ 哪怕你从没调用过这个静态方法,它也一直占着空间,和枚举的 "提前占内存" 是同一个问题
  2. 而非静态方法(DCL 单例):
    • 类加载时,只加载类的元信息,非静态方法的执行逻辑不占内存
    • 只有第一次调用方法时,才创建单例对象,非静态方法才真正占内存
    • 完全符合 "什么时候用,什么时候才占内存" 的优化需求

简单示例说明:

java 复制代码
// 静态方法版(提前占内存)
class ServletStatic {
    // 类加载后,这个静态方法就占内存,哪怕从没调用过
    public static void doGet() {}
}

// DCL 非静态版(按需占内存)
class ServletDCL {
    private volatile static ServletDCL INSTANCE;
    private ServletDCL() {}

    public static ServletDCL getInstance() {
        if (INSTANCE == null) { // 第一次调用才创建对象
            synchronized (ServletDCL.class) {
                if (INSTANCE == null) {
                    INSTANCE = new ServletDCL(); // 此时非静态方法才占内存
                }
            }
        }
        return INSTANCE;
    }

    // 非静态方法:只有创建对象后才占内存
    public void doGet() {}
}

此外,静态方法无法被重写,灵活性远低于非静态方法,也不符合 Servlet/Controller 可扩展的开发需求。

通过上面的对比我们可以发现,非静态方法必须依托对象才能调用,而想要保证单例的内存优化效果,首先就要从根源上控制对象的创建数量,这就涉及到单例模式最基础的设计:构造方法私有

这就留到下一篇我们再来讲一讲~

并发编程(二十四):单例模式(三):构造方法私有:单例模式的 "第一道防线"-CSDN博客

相关推荐
Dicky-_-zhang几秒前
Java并发编程实战:线程池与并发工具类
java·jvm
devilnumber1 分钟前
JDK6→JDK7→JDK8 重点技术更新(精简背诵版)
java
云烟成雨TD2 分钟前
Spring AI Alibaba 1.x 系列【61】Graph 持久化执行
java·人工智能·spring
muqsen2 分钟前
Java 分布式相关面试题总结
java·开发语言·分布式
做个文艺程序员4 分钟前
第02篇:搭建 ES 集群 + Spring Boot 整合实战——从 Docker Compose 到 Java 客户端全覆盖
java·spring boot·elasticsearch
Jinkxs5 分钟前
LoadBalancer- 简单限流策略:Nginx 基于连接 / 请求的限流实现
java·运维·nginx
fenglllle13 分钟前
JDK8升级JDK17使用CompletableFuture在线程中classloader的变化
java·开发语言·jvm
计算机安禾13 分钟前
【c++面向对象编程】第44篇:typename与class的区别,依赖类型名与template消除歧义
java·jvm·c++
JAVA面经实录91722 分钟前
Java+SpringAI企业级实战项目完整官方文档(生产终版)
java·开发语言·spring·ai编程
梵得儿SHI22 分钟前
Java IO 流进阶:Buffer 与 Channel 核心概念解析及与传统 IO 的本质区别
java·开发语言·高并发·nio·channel·buffer·提升io效率