Java单例模式的实现
饿汉式
线程安全,由jvm类加载时初始化,保证线程安全
public class EagerSingleton { // static保证唯一,final保证不可变 private static final EagerSingleton INSTANCE = new EagerSingleton(); private EagerSingleton(){} public static EagerSingleton getInstance(){ return INSTANCE; } }
懒汉式
懒加载,线程不安全,因为实例化对象有个判断的过程,但是可以加个synchronized
来保证线程安全。
public class LazySingleton { // 由于需要懒加载,不能使用final关键字,需要自己保证安全 private static LazySingleton INSTANCE; private LazySingleton() {} // public static synchronized LazySingleton getInstance() { public static LazySingleton getInstance() { if(INSTANCE == null){ INSTANCE = new LazySingleton(); } return INSTANCE; } }
双重检查锁
线程安全,使用 volatile
关键字确保多线程环境下的可见性
public class DoubleCheckSingleton { private static volatile DoubleCheckSingleton INSTANCE; private DoubleCheckSingleton() {} public static DoubleCheckSingleton getInstance() { if (INSTANCE == null) { synchronized (DoubleCheckSingleton.class) { if (INSTANCE == null){ INSTANCE = new DoubleCheckSingleton(); } } } return INSTANCE; } }
静态内部类
既保证了线程安全,又是延迟加载。
- 将单例实例放在静态内部类中:
静态内部类在外部类加载时不会初始化,只有在调用 getInstance() 时才会加载并初始化静态内部类,从而实现延迟初始化。 - 利用类加载机制保证线程安全:
JVM 在加载类时会自动加锁,保证类加载过程的线程安全性,因此静态内部类的初始化是线程安全的。
静态内部类的特性
静态内部类是定义在另一个类内部的静态类。它有以下特点:
- 静态内部类是独立于外部类的:
静态内部类与外部类的实例无关,可以直接通过外部类名访问。 - 静态内部类在加载时不会初始化:
静态内部类只有在被主动使用
时才会加载
和初始化
。
public class InnerSingleton { private InnerSingleton() {} private static class SingletonHolder { private static final InnerSingleton INSTANCE = new InnerSingleton(); } public static InnerSingleton getInstance() { return SingletonHolder.INSTANCE; } }
枚举类
枚举单例的优势
- 线程安全:
枚举实例的创建由 JVM 保证线程安全,无需额外同步。 - 防止反射破坏单例:
枚举类的构造函数是私有的,且JVM
禁止通过反射创建枚举实例。 - 防止序列化破坏单例:
枚举类的序列化和反序列化由JVM 保证
,不会创建新的实例。 - 代码简洁:
枚举单例的实现非常简单,只需几行代码。
public enum EnumSingleton { INSTANCE; // 单例实例 // 可以添加其他方法和属性 public void doSomething() { System.out.println("Singleton instance is doing something!"); } }
扩展一下
public enum Singleton { INSTANCE; private String name; // 可以添加方法 public void setName(String name) { this.name = name; } public String getName() { return name; } public void doSomething() { System.out.println("Singleton instance is doing something!"); } }
使用示例:
public class Main { public static void main(String[] args) { Singleton instance = Singleton.INSTANCE; instance.setName("Singleton Example"); System.out.println("Name: " + instance.getName()); // 输出: Name: Singleton Example instance.doSomething(); // 输出: Singleton instance is doing something! } }
本文来自博客园,作者:chendsome,转载请注明原文链接:https://www.cnblogs.com/chendsome/p/18718432
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)