本文最后更新于 106 天前 ,文中信息可能已经过时。如有问题请在评论区留言。

单例模式(Singleton Pattern)是一种创建型设计模式,确保一个类只有一个实例,并提供全局访问点。 Java 中实现单例模式有多种方法,每种方法各有优缺点。以下是几种常见的实现方法及其最佳实践。

饿汉式单例

饿汉式在 类加载时就创建实例,线程安全。

java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public class Singleton {
    private static final Singleton INSTANCE = new Singleton();

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

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

优点

  • 简单直观
  • 线程安全

缺点

  • 类加载时就创建实例,如果实例未使用,可能浪费内存

懒汉式单例(线程不安全)

懒汉式在第一次需要实例时才创建,线程不安全。

java
 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;
    }
}

优点

  • 延迟加载,只有在需要时创建实例

缺点

  • 线程不安全,多线程环境下可能创建多个实例

线程安全的懒汉式单例

通过同步方法实现线程安全:

java
 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 都要进行同步

双重检查锁定(Double-Checked Locking)

双重检查锁定减少了同步的开销。

java
 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;
    }
}

优点

  • 线程安全
  • 延迟加载
  • 性能较高,只有第一次创建实例时同步。

缺点

  • 需要注意使用 volatile 关键字,防止指令重排

静态内部类

利用类加载机制确保线程安全,同时实现懒加载。

java
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
public class Singleton {
    private Singleton() {}

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

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

优点

  • 线程安全
  • 延迟加载
  • 实现简单

缺点

  • 无法处理带参数的单例

枚举单例

枚举实现单例模式天生是线程安全的,并且防止反序列化导致重新创建新的对象。

java
1
2
3
4
5
6
7
public enum Singleton {
    INSTANCE;

    public void doSomething() {
        // do something
    }
}

优点

  • 线程安全
  • 防止反序列化
  • 简单,且能防止反射攻击

缺点

  • 某些情况不适用,比如需要继承某个类

总结

在实际项目中,推荐使用静态内部类和枚举单例,因为它们既简单又安全,性能较高。具体选择哪种方式需要根据实际需求来决定。