实现 Java 线程安全的 Singleton 模式

在 Java 开发中,实现一个线程安全的单例模式(Singleton)是非常重要的。下面我会逐步引导你实现这个目标。整个过程分为几个步骤,我们将会在每个步骤中讨论具体的代码实现以及该代码的作用。

步骤流程表

我们可以将实现过程梳理成以下流程:

步骤 描述
1 创建 Singleton 类
2 定义私有构造函数
3 创建一个静态私有实例
4 提供一个公共静态方法
5 实现线程安全
6 测试该 Singleton 类

1. 创建 Singleton 类

首先,我们需要创建一个 Singleton 类,这个类将会持有单一实例。

public class Singleton {
    // 声明一个静态私有变量来保存实例
    private static Singleton instance;

    // 私有构造函数,禁止外部创建实例
    private Singleton() {}

    // 公共静态方法返回实例
    public static Singleton getInstance() {
        if (instance == null) {  // 第一次检查
            instance = new Singleton(); // 创建实例
        }
        return instance; // 返回实例
    }
}

2. 定义私有构造函数

在上面的代码中,构造函数是私有的,意义在于禁止其他类直接创建 Singleton 对象。这是单例模式的关键步骤。

3. 创建静态私有实例

我们定义一个静态变量 instance 来存储 Singleton 的唯一实例。

4. 提供一个公共静态方法

getInstance() 方法检查是否已存在实例,如果没有,则创建一个。这是外界获取 Singleton 实例的方式。

5. 实现线程安全

为了确保在多线程环境下只创建一个实例,我们需要对 getInstance() 方法的实现进行改进。

我们可以使用双重检查锁定(Double-Checked Locking)。具体如下:

public class Singleton {
    private static Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        // 第一次检查
        if (instance == null) {
            synchronized (Singleton.class) { // 同步块
                // 第二次检查
                if (instance == null) {
                    instance = new Singleton(); // 创建实例
                }
            }
        }
        return instance; // 返回实例
    }
}

在这个实现中:

  • 我们首先检查 instance 是否为 null
  • 如果是 null,则进入 synchronized 块。
  • synchronized 块内,我们再次检查 instance 是否为 null。如果仍然为 null,则创建实例。

6. 测试该 Singleton 类

最后,我们需要测试 Singleton 类,确保它是线程安全的。

public class SingletonTest {
    public static void main(String[] args) {
        Runnable task = () -> {
            Singleton instance = Singleton.getInstance();
            System.out.println(instance);
        };

        // 创建多个线程来测试 Singleton
        for (int i = 0; i < 10; i++) {
            new Thread(task).start();
        }
    }
}

在上面的 SingletonTest 类中,我们创建了多个线程来调用 getInstance() 方法并打印出实例。你会发现,无论多少线程并发访问,始终得到的是同一个实例。

类图示例

我们可以用 mermaid 语法表示相关的类图结构:

classDiagram
    class Singleton {
        <<Singleton>>
        - static Singleton instance
        - Singleton()
        + static Singleton getInstance()
    }

结尾

在这篇文章中,我们介绍了如何实现一个线程安全的 Singleton 模式。通过明确的步骤和代码示例,我相信你能够独立完成这个实现。无论是应用于大型项目,还是小型练习,Singleton 模式都将是你的有效工具。继续学习和实践,你会在 Java 开发中逐渐得心应手!