Java 基础-30-单例设计模式:懒汉式与饿汉式

在软件开发中,单例设计模式(Singleton Design Pattern)是一种常用的设计模式,它确保一个类只有一个实例,并提供一个全局访问点。这种模式通常用于管理共享资源(如数据库连接池、线程池等)或需要全局唯一实例的场景。

本文将详细介绍两种常见的单例实现方式:懒汉式 和饿汉式,并分析它们的优缺点及适用场景。


1. 单例模式的核心要素

要实现单例模式,需要满足以下三个条件:

  1. 私有化构造方法 :防止外部通过new关键字创建对象。
  2. 提供静态方法获取唯一实例:通过一个公共的静态方法返回唯一的实例。
  3. 保持单一实例:确保类中只有一个实例存在。

2. 饿汉式(Eager Initialization)

饿汉式是指在类加载时就立即创建实例。这种方式的特点是简单直接,但可能会造成资源浪费(如果实例从未被使用过)。

实现代码

复制代码
public class SingletonEager {
    // 1. 私有化构造方法
    private SingletonEager() {
        System.out.println("SingletonEager instance created");
    }

    // 2. 在类加载时创建唯一的实例
    private static final SingletonEager instance = new SingletonEager();

    // 3. 提供公共的静态方法获取实例
    public static SingletonEager getInstance() {
        return instance;
    }
}

特点

  • 优点 :
    • 简单易懂,实现方便。
    • 线程安全(因为实例在类加载时就已经创建,不存在多线程竞争问题)。
  • 缺点 :
    • 如果实例从未被使用过,会浪费内存资源。
    • 不适合需要延迟加载的场景。

3. 懒汉式(Lazy Initialization)

懒汉式 是指在第一次调用getInstance()方法时才创建实例。这种方式可以避免资源浪费,但需要注意线程安全问题。

实现代码(非线程安全版本)

复制代码
public class SingletonLazy {
    // 1. 私有化构造方法
    private SingletonLazy() {
        System.out.println("SingletonLazy instance created");
    }

    // 2. 定义静态变量,但不立即初始化
    private static SingletonLazy instance;

    // 3. 提供公共的静态方法获取实例
    public static SingletonLazy getInstance() {
        if (instance == null) { // 第一次检查
            instance = new SingletonLazy(); // 创建实例
        }
        return instance;
    }
}

特点

  • 优点 :
    • 延迟加载,节省资源。
  • 缺点 :
    • 存在线程安全问题(多线程环境下可能创建多个实例)。
线程安全改进版(双重检查锁定)

为了解决线程安全问题,可以使用双重检查锁定(Double-Checked Locking)机制:

复制代码
public class SingletonLazySafe {
    // 1. 私有化构造方法
    private SingletonLazySafe() {
        System.out.println("SingletonLazySafe instance created");
    }

    // 2. 使用volatile关键字保证可见性和禁止指令重排
    private static volatile SingletonLazySafe instance;

    // 3. 双重检查锁定
    public static SingletonLazySafe getInstance() {
        if (instance == null) { // 第一次检查
            synchronized (SingletonLazySafe.class) {
                if (instance == null) { // 第二次检查
                    instance = new SingletonLazySafe();
                }
            }
        }
        return instance;
    }
}

特点

  • 优点 :
    • 延迟加载,节省资源。
    • 线程安全。
  • 缺点 :
    • 实现复杂度较高。

4. 对比:懒汉式 vs 饿汉式

特性 饿汉式 懒汉式
实例创建时机 类加载时 第一次调用getInstance()时
资源占用 可能浪费资源 延迟加载,节省资源
线程安全性 天然线程安全 需额外处理(如双重检查锁定)
实现复杂度 简单 较复杂
适用场景 实例一定会被使用且对性能要求高 实例可能不会被使用或需延迟加载

5. 其他实现方式(扩展)

除了懒汉式和饿汉式,还有其他常见的单例实现方式,例如:

枚举单例

复制代码
public enum SingletonEnum {
    INSTANCE;

    public void doSomething() {
        System.out.println("Doing something...");
    }
}
  • 优点:天然线程安全,防止反射攻击,简洁优雅。
  • 缺点:功能有限,不适合需要继承的场景。

静态内部类

复制代码
public class SingletonInnerClass {
    private SingletonInnerClass() {}

    private static class SingletonHolder {
        private static final SingletonInnerClass INSTANCE = new SingletonInnerClass();
    }

    public static SingletonInnerClass getInstance() {
        return SingletonHolder.INSTANCE;
    }
}
  • 优点:延迟加载,线程安全,性能较好。
  • 缺点:实现稍复杂。

6. 总结

  • 饿汉式适合于实例一定会被使用的场景,简单高效,但可能会浪费资源。
  • 懒汉式适合于实例可能不会被使用的场景,可以延迟加载,但需要注意线程安全问题。
  • 如果追求简洁和安全性,推荐使用枚举单例 或静态内部类实现。
相关推荐
云和数据.ChenGuang7 小时前
LLM大模型对接本地Ollama部署模型
开发语言·人工智能·python·langchain
文丑颜不良啊7 小时前
LeetCode276~300题目解析
java·leetcode
Vegetable_xu7 小时前
Spring Bean 循环依赖:为什么有时能过、有时启动就挂
java·spring·mybatis
等我调个Bug7 小时前
C++智能指针通俗讲解
开发语言·c++
黑化旺仔8 小时前
【OC】Runtime:类元数据、加载初始化与消息派发
开发语言·macos·ios·objective-c
Felven8 小时前
C. Removing Smallest Multiples
c语言·开发语言
云和数据.ChenGuang8 小时前
光哥说Python 循环导入(Circular Import)深度解析:成因、排查与解决方案
开发语言·前端·人工智能·python·langchain
星夜离尘568 小时前
MATLAB 工程实验:滞回加持续时间报警,把 UNKNOWN 留在状态机里
开发语言·matlab
avi91118 小时前
【AI教人】在Inspector显示所有Delegate-Odin Inspector之三
java·前端·算法·delegate·inspector·editor扩展·unity editor
fengci.8 小时前
BUUCTF(困难部分)
android·开发语言·前端·学习·php