Java实际项目使用的Singleton是什么样的

java面试经常问的一个问题就是单例怎么实现,这个问题主要考察的就是延迟加载和java的内存机制,按照通常的标准答案是这样的:

class Singleton {
  private static volatile Singleton value;
  private Singleton() {}
  public static Singleton get() {
    if (value == null) {
      synchronized(Singleton.class) {
        if (value == null) {
          value = new Singleton();
        }
        return value;
      }
    }
  }
}

这个方法理论上是没问题的,但是实际使用中,是有问题的。

首先,一个singleton就要写一个类,对于大一点的项目,有可能有多个使用单例的场景,岂不是每个都要写一个Singleton类,这就麻烦了。
其次,可以看到这个单例的构造函数是private,但是平时写的类,几乎不可能只有一个private的构造函数。
总之,这种写法不太实用,主要还是在面试时考察面试者对Java的基础是否了解。

实际的单例是怎么样的,可以参考spring的源码

public class SingletonSupplier implements Supplier {

    @Nullable
    private final Supplier instanceSupplier;

    @Nullable
    private final Supplier defaultSupplier;

    @Nullable
    private volatile T singletonInstance;

  @Override
    @Nullable
    public T get() {
        T instance = this.singletonInstance;
        if (instance == null) {
            synchronized (this) {
                instance = this.singletonInstance; 
                if (instance == null) {
                    if (this.instanceSupplier != null) {
                        instance = this.instanceSupplier.get();
                    }
                    if (instance == null && this.defaultSupplier != null) {
                        instance = this.defaultSupplier.get();
                    }
                    this.singletonInstance = instance;
                }
            }
        }
        return instance;
    }
}

可以看到,实际情况下,Spring并没有每个需要单例的地方都写一个单例,而是提供一个supplier来创建单例。

这里还有一个小技巧,因为this.singletonInstance已经被volatile修饰,读this.singletonInstance是从主内存读取,这里赋值给instance,只用读一次,速度更快。

当然,如果要确保严格的单例,那么还要确保SingletonSupplier的对象也是单例的,但是从Spring代码看,并没有这么严格,只要求每个对象的singletonSupplier.get()返回的是单例。

你可能感兴趣的:(Java实际项目使用的Singleton是什么样的)