解决思路

  • 饿汉模式
  • 懒汉模式
  • 改良的懒汉模式:基于类初始化的方式(Initialization On Demand Holder Idiom)
  • 双重检查锁模式(Double Checked Locking Pattern)

饿汉模式

  1. public class Singleton {
  2. private static Singleton instance = new Singleton();
  3. private Singleton(){}
  4. public static Singleton getInstance() {
  5. return instance;
  6. }
  7. }

特点:

  • 使用静态初始化

优点:

  • 实现简单
  • 没有锁竞争

缺点:

  • 在类被加载时就会初始化,如果加载类的目的不是获取实例(比如存在静态成员INFO,有代码调用了Singleton.INFO),就会浪费内存空间

懒汉模式

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

特点:

  • 在调用getInstance时初始化

优点:

  • 不会造成空间的浪费
  • 实现也简单

缺点:

  • 每次获取实例都要获取锁,浪费时间

改良版懒汉模式:基于类初始化的方式

  1. public class LazySingleton2 {
  2. private LazySingleton2() {}
  3. private static class SingletonHolder {
  4. private static LazySingleton2 instance = new LazySingleton2();
  5. }
  6. public static LazySingleton2 getInstance() {
  7. return SingletonHolder.instance;
  8. }
  9. }

特点:

  • 将实例放入静态内部类中,只有调用获取实例的方法时instance才会初始化

优点:

  • 不会造成空间浪费
  • 没有锁竞争
  • 实现也不算复杂

缺点:

  • JVM会多加载一个类

    双重检查锁模式

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

特点:

  • 使用二次检查减少获取锁的次数,从而优化性能
  • 必须使用volatile保证编译器不对代码执行顺序进行优化

优点:

  • 惰性加载,不浪费空间
  • 二次检查,思想与乐观锁类似,竞争不激烈的情况下,几乎相当于无锁
  • 不会加载多余的类

缺点:

  • 编码细节较之前的方法比较多
  • 在Java 1.5之前不能保证功能可靠

推荐使用

  • 单例类没有其他公开的静态成员或静态方法、单例一定在最开始的时候就会被加载 => 使用饿汉模式
  • 其余情况 => 改良的懒汉模式
  • double check细节太多,不建议使用