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!
}
}
posted @   chendsome  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示