单例模式是面向对象设计模式中的一种,它保证一个类仅有一个实例,并提供一个全局访问点。在 Java 中实现单例模式通常有以下几种方法:

1. 饿汉式(静态常量)

这是最简单的实现方式,类加载时就创建实例。

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

    private Singleton() {}

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

2. 懒汉式(线程不安全)

当首次调用 getInstance() 方法时才创建实例,但在多线程环境下可能创建多个实例。

public class Singleton {
    private static Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

3. 懒汉式(双重检查锁定,线程安全)

利用 volatile 关键字和双重检查锁定(Double-Checked Locking)来确保线程安全并延迟实例化。

public class Singleton {
    private volatile static Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

4. 静态内部类

利用 Java 的类加载机制保证初始化实例时只有一个线程,从而实现线程安全,同时也实现了懒加载。

public class Singleton {
    private Singleton() {}

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

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

5. 枚举

从 Java 5 开始,枚举可以被视为一个更好的单例模式的实现方式,因为枚举天然支持序列化机制,防止反射攻击,并且是线程安全的。

public enum Singleton {
    INSTANCE;

    // 可以在这里定义实例变量
    private String data;

    // 构造器私有化,枚举类型的构造器默认就是私有的
    // 这里只是为了明确展示,实际上不需要显示声明
    private Singleton() {
        this.data = "Hello, World!";
    }

    // 提供公共方法来访问实例变量
    public String getData() {
        return data;
    }

    // 可以添加其他业务逻辑方法
    public void someMethod() {
        System.out.println("This is a singleton instance: " + this);
    }
}

// 使用示例
public class SingletonDemo {
    public static void main(String[] args) {
        Singleton singleton = Singleton.INSTANCE;
        System.out.println(singleton.getData());
        singleton.someMethod();
    }
}

选择单例模式时的考虑因素:

  • 性能:饿汉式在类加载时就创建实例,可能会浪费资源。而懒汉式在首次需要时创建,节省资源但可能有性能开销。
  • 线程安全性:非线程安全的懒汉式在多线程环境下可能导致多个实例的创建,而双重检查锁定或静态内部类方式则可解决此问题。
  • 延迟加载:如果你确定单例对象不会被立即使用,那么使用懒加载的模式可以节省资源。
  • 代码简洁性:枚举实现是最简洁和最安全的实现方式之一。

在实际应用中,根据具体需求选择合适的单例实现方式。例如,在需要延迟初始化且要确保线程安全的情况下,双重检查锁定或静态内部类是较好的选择。而在不需要延迟加载的情况下,枚举或饿汉式可以简化代码结构。

更多推荐