跳转至

Java 单例模式示例详解

简介

在软件开发中,设计模式是经过反复实践总结出来的通用解决方案,能够帮助开发者更高效地构建软件系统。单例模式(Singleton Pattern)是一种创建型设计模式,它确保一个类只有一个实例,并提供一个全局访问点来访问这个实例。在 Java 中,单例模式应用广泛,例如在数据库连接池、日志记录器等场景中,保证系统中某个关键资源只有一个实例,避免资源浪费和不一致性。

目录

  1. 单例模式基础概念
  2. 单例模式的使用方法
  3. 常见实践示例
    • 饿汉式单例
    • 懒汉式单例
    • 双重检查锁单例
    • 静态内部类单例
    • 枚举单例
  4. 最佳实践
  5. 小结
  6. 参考资料

单例模式基础概念

单例模式有三个关键特性: 1. 一个实例:确保一个类在系统中只有一个实例。 2. 全局访问点:提供一个全局的静态方法,方便其他对象获取这个实例。 3. 自行实例化:类自身负责创建并管理这个唯一实例。

单例模式的使用方法

在 Java 中实现单例模式,通常需要以下步骤: 1. 将类的构造函数声明为私有,防止外部通过 new 关键字创建实例。 2. 在类内部创建一个静态的实例变量,用于存储唯一的实例。 3. 提供一个公共的静态方法,用于获取这个实例。

常见实践示例

饿汉式单例

饿汉式单例在类加载时就创建实例,不管是否需要使用。

public class EagerSingleton {
    // 静态常量,在类加载时创建实例
    private static final EagerSingleton INSTANCE = new EagerSingleton();

    // 私有构造函数,防止外部实例化
    private EagerSingleton() {}

    // 公共静态方法,返回唯一实例
    public static EagerSingleton getInstance() {
        return INSTANCE;
    }
}

懒汉式单例

懒汉式单例在第一次调用 getInstance 方法时才创建实例。

public class LazySingleton {
    // 静态变量,用于存储实例
    private static LazySingleton instance;

    // 私有构造函数,防止外部实例化
    private LazySingleton() {}

    // 公共静态方法,返回唯一实例
    public static LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}

双重检查锁单例

双重检查锁单例在多线程环境下保证高效且安全的实例创建。

public class DoubleCheckedLockingSingleton {
    // 静态变量,使用 volatile 关键字防止指令重排
    private static volatile DoubleCheckedLockingSingleton instance;

    // 私有构造函数,防止外部实例化
    private DoubleCheckedLockingSingleton() {}

    // 公共静态方法,返回唯一实例
    public static DoubleCheckedLockingSingleton getInstance() {
        if (instance == null) {
            synchronized (DoubleCheckedLockingSingleton.class) {
                if (instance == null) {
                    instance = new DoubleCheckedLockingSingleton();
                }
            }
        }
        return instance;
    }
}

静态内部类单例

静态内部类单例利用了 Java 类加载机制的特性,实现延迟加载且线程安全。

public class StaticInnerClassSingleton {
    // 私有构造函数,防止外部实例化
    private StaticInnerClassSingleton() {}

    // 静态内部类,在外部类被加载时不会加载
    private static class SingletonHolder {
        private static final StaticInnerClassSingleton INSTANCE = new StaticInnerClassSingleton();
    }

    // 公共静态方法,返回唯一实例
    public static StaticInnerClassSingleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

枚举单例

枚举单例是 Java 中实现单例模式最简单且最安全的方式,枚举类型本身就是线程安全的。

public enum EnumSingleton {
    INSTANCE;

    // 可以添加其他方法
    public void doSomething() {
        System.out.println("Doing something in EnumSingleton");
    }
}

最佳实践

  1. 线程安全:在多线程环境下,确保单例模式的实现是线程安全的,如双重检查锁单例、静态内部类单例和枚举单例。
  2. 延迟加载:如果实例创建开销较大,尽量选择延迟加载的实现方式,如懒汉式单例(注意多线程问题)、静态内部类单例。
  3. 序列化与反序列化:如果单例对象需要进行序列化和反序列化,需要确保反序列化时不会创建新的实例。枚举单例在这方面有天然的优势,其他实现方式需要额外处理。

小结

单例模式是 Java 中一种重要的设计模式,它提供了一种创建和管理唯一实例的方式。不同的实现方式各有优缺点,开发者需要根据具体的应用场景选择合适的单例模式。饿汉式单例简单直接,但可能造成资源浪费;懒汉式单例实现延迟加载,但在多线程环境下需要额外处理;双重检查锁单例、静态内部类单例和枚举单例在多线程环境下表现良好,且枚举单例在序列化和反序列化方面更为安全。

参考资料

  1. 《Effective Java》 - Joshua Bloch
  2. Oracle Java 教程
  3. 维基百科 - 单例模式