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<T> implements Supplier<T> {

    @Nullable
    private final Supplier<? extends T> instanceSupplier;

    @Nullable
    private final Supplier<? extends T> 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()返回的是单例。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容