Java 三种方式实现单例模式

单例模式是一种常见的设计模式,它用于确保一个类只有一个实例,并提供全局访问点。在许多情况下,我们可能需要确保一个类只能创建一个对象,并且能够全局访问这个对象。单例模式正是为了满足这种需求而生。在Java中,实现单例模式的方式多种多样,包括懒汉式、饿汉式、双重检查锁定、静态内部类等。本文将总结和讨论这些方式的实现、优缺点以及线程安全性,并提供一种使用枚举类来实现单例模式的方式。通过本文的介绍,读者将能够深入了解单例模式的各种实现方式,以及在不同情况下如何选择合适的单例模式实现方法。

1. 双重检查锁

Java 单例模式中的双重检查锁(Double-Checked Locking)是一种常见的实现方式,旨在确保线程安全的同时提高性能。

csharp 复制代码
class Singleton {
    private static volatile Singleton singleton;

    private Singleton() {}

    public Singleton get() {
        if (singleton == null) {
            synchronized (this) {
                if (singleton == null) {
                    return new Singleton();
                }
            }
        }

        return singleton;
    }
}

针对双重检查锁的详细解读:

  • volatile 关键词:避免JVM的指令重排。
  • synchronized 关键词:避免并发 new 对象,导致对象被覆盖。
  • singleton == null 外层校验:单例对象创建出来后就不需要进入synchronized的锁逻辑了,提高读取效率。
  • singleton == null 内层校验:避免进入synchronized关键词后对象的重复创建。

双重检查锁的问题:使用volatile关键字能保证执行顺序,但是在一定程度上会影响执行效率。

2. 静态内部类

双重检查锁是一种有效且常用的单例模式实现方式,但在某些情况下可能会遇到无序写问题。为确保线程安全和避免潜在问题,建议使用静态内部类的方式来实现单例模式。这种方式不仅简洁高效,还能确保在任何情况下都能正确地创建和访问单例实例。

csharp 复制代码
public class Singleton {
    private Singleton() {}

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

    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

优点:

  1. 线程安全:静态内部类的初始化是线程安全的,由 JVM 保证。
  2. 延迟加载 :只有在第一次访问 getInstance() 方法时才会加载内部类并创建实例。
  3. 简洁高效 :无需显式使用 synchronized 关键字,减少了代码复杂度。

3. 枚举

在Java中,我们也可以使用枚举类来实现单例模式。由于枚举类的特性保证了只有一个枚举常量对象,因此可以通过枚举类来实现单例模式,且代码简洁且具有线程安全的特性。

csharp 复制代码
public enum Singleton {
    INSTANCE;  // 唯一的枚举实例

    // 添加其他属性或方法
    public void doSomething() {
        // 具体操作
    }
}

使用枚举类实现单例模式的好处是简洁、安全且可靠。不过,在我们一般的业务系统中,枚举类往往都是由自己的语义的,用枚举类实现单例模式并不常见。

相关推荐
后台模板学习3 分钟前
学习的心态高频面试题
java·数据库·学习
周杰伦fans5 分钟前
ASP.NET Core Identity 从入门到实战:常见问题与解决方案
后端·asp.net
n8n25 分钟前
Spring AI 三层架构详解:ChatModel → ChatClient → Controller,同步调用 vs 流式调用(SSE)
后端
用户31268748772028 分钟前
线程池到底怎么管理线程的?从 ThreadPoolExecutor 到拒绝策略全链路拆解
java
小傅哥30 分钟前
Java + DDD,1:1 复刻 Deepseek Harness 项目
前端·后端·ai编程
Ysx31 分钟前
AI 问答不再"一本正经地胡说":30 轮提示词迭代,沉淀 4 条防幻觉铁律
设计模式
Lambert28131 分钟前
AgentScope Java 从零(03):Agent 的记性默认全开,我在第 50 轮翻了车
后端·aigc
积硅步致千里38 分钟前
Word 里的 .wmf 其实是 EMF:一次 metafile 转 PNG 排障
前端·后端
cpolar技术支持42 分钟前
Kafka Streams 窗口统计怎么验收:本地跑订单流聚合,用 cpolar 给同事看只读结果页
java·docker·kafka·cpolar·kafka streams
爱读源码的大都督1 小时前
DeepSeek面试官问:生产RAG系统回答不准确,该如何定位和优化?这样回答,能让面试官当场给你Offer!
java·后端·python