饿汉式和懒汉式的单例模式

参考: 设计模式之单例模式(七种方法超详细)

单例模式是一种常用的软件设计模式,用于确保一个类只有一个实例,并提供一个全局访问点。饿汉式和懒汉式是单例模式的两种实现方式,它们的主要区别在于实例的创建时机

饿汉式单例模式

特点:

  • 在类加载时就初始化实例,因此也被称为“急切式”或“饿汉式”。
  • 线程安全,因为实例在类加载时就已经创建,不会出现多线程并发创建实例的问题。
  • 缺点是实例的创建不依赖于实际需求,可能会占用不必要的资源。

实现代码(Java 示例):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public class Singleton {
    // 在类加载时初始化实例
    private static final Singleton instance = new Singleton();

    // 私有化构造函数,防止外部通过 new 创建实例
    private Singleton() {}

    // 提供一个全局访问点
    public static Singleton getInstance() {
        return instance;
    }
}

懒汉式单例模式

特点:

  • 实例的创建是“懒惰”的,即只有在第一次调用 getInstance() 方法时才会创建实例。
  • 需要处理线程安全问题,否则在多线程环境下可能会创建多个实例。

实现方式:

  • 非线程安全的懒汉式:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    public class Singleton {
        private static Singleton instance;
    
        private Singleton() {}
    
        public static Singleton getInstance() {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    }
    

    这种实现方式在多线程环境下是不安全的,可能会导致多个实例被创建。

  • 线程安全的懒汉式(加锁):

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    
    public class Singleton {
        private static Singleton instance;
    
        private Singleton() {}
    
        public static synchronized Singleton getInstance() {
            if (instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    }
    

    这种方式虽然线程安全,但每次调用 getInstance() 方法时都会加锁,效率较低。

  • 双重校验锁(DCL):

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    
    public class Singleton {
        private static volatile Singleton instance;
    
        private Singleton() {}
    
        public static Singleton getInstance() {
            if (instance == null) { // 第一次检查
                synchronized (Singleton.class) { // 加锁
                    if (instance == null) { // 第二次检查
                        instance = new Singleton();
                    }
                }
            }
            return instance;
        }
    }
    

    这种方式既保证了线程安全,又避免了每次调用都加锁,效率较高。

总结

  • 饿汉式:线程安全,但实例在类加载时就创建,可能会浪费资源。
  • 懒汉式:实例按需创建,但需要处理线程安全问题。其中,双重校验锁(DCL)是懒汉式的最佳实现方式。

在实际开发中,选择哪种单例模式取决于具体需求。如果实例创建成本不高且类加载时就可初始化,可以选择饿汉式;如果需要按需创建实例且线程安全很重要,则推荐使用双重校验锁实现的懒汉式。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计