深入理解单例模式之饿汉式与懒汉式

作者:狼烟四起2024.01.17 11:45浏览量:34

简介:单例模式是一种常用的设计模式,确保一个类只有一个实例,并提供一个全局访问点。本文将详细解释单例模式的饿汉式和懒汉式实现方式,并通过实例代码帮助读者理解。

单例模式是一种常见的设计模式,它的主要目的是确保一个类只有一个实例,并提供一个全局访问点。这样可以避免重复实例化对象,提高性能和资源利用率。单例模式通常用于日志记录、缓存、数据库连接等场景。
单例模式有两种常见的实现方式:饿汉式和懒汉式。下面我们将分别介绍这两种方式。
饿汉式
饿汉式是在类加载时就完成了初始化,所以类加载比较慢,但获取对象的速度快。这种方式适用于线程安全的环境。

  1. public class Singleton {
  2. // 在类加载时就完成了初始化,所以类加载比较慢
  3. private static Singleton instance = new Singleton();
  4. private Singleton() {}
  5. public static Singleton getInstance() {
  6. return instance;
  7. }
  8. }

懒汉式
懒汉式是在第一次调用 getInstance() 方法时初始化对象,所以类加载速度快,但获取对象的速度慢。这种方式适用于多线程环境。

  1. public class Singleton {
  2. // 类加载时不初始化
  3. private static Singleton instance;
  4. private Singleton() {}
  5. // 在第一次调用时初始化对象
  6. public static synchronized Singleton getInstance() {
  7. if (instance == null) {
  8. instance = new Singleton();
  9. }
  10. return instance;
  11. }
  12. }

需要注意的是,在多线程环境下,懒汉式可能会导致多个实例的情况,因为两个线程可能在同一时刻进入 if (instance == null) 判断语句并同时创建实例。为了避免这种情况,可以使用 synchronized 关键字进行同步,但这会降低性能。因此,通常会结合双重检查锁定(double-checked locking)机制来解决这个问题。
双重检查锁定机制的代码如下:

  1. public class Singleton {
  2. private volatile static Singleton instance; // 使用volatile关键字保证可见性
  3. private Singleton() {}
  4. public static Singleton getInstance() {
  5. if (instance == null) { // 第一次检查实例是否为空
  6. synchronized (Singleton.class) { // 使用类对象作为锁对象,保证同一时刻只有一个线程可以进入同步块
  7. if (instance == null) { // 第二次检查实例是否为空,只有在第一次检查为空时才会进入同步块,避免了不必要的同步开销
  8. instance = new Singleton(); // 创建实例并赋值给instance变量
  9. }
  10. }
  11. }
  12. return instance; // 返回实例对象
  13. }
  14. }

通过双重检查锁定机制,我们可以在多线程环境下安全地实现单例模式,同时避免了不必要的同步开销。需要注意的是,使用 volatile 关键字可以保证可见性,即一个线程修改了 instance 变量的值后,其他线程能够立即看到修改后的值。这是因为在 Java 中,volatile 关键字可以禁止指令重排序优化,保证变量的可见性和有序性。