枚举表演中的单身人士

时间:2017-11-27 00:13:30

标签: java multithreading enums

我想知道枚举中的单身人物及其表现。

当我们有多线程环境时,我们必须在创建实例时同步时刻。

简单地说,我们可以使用synchronized mod,用于创建实例的名为getInstance()的函数 有些想法:

public synchronized Singleton getInstance(){
    if(instance == null){
        instance = new Singleton();
    }
    return instance;
}

它的实施很懒,对我有好处。但是同步方法很慢。 我们可以使用双锁来加快速度。

枚举怎么样? 当我们将单例实现为枚举时,将首次使用单例实例。下次使用,返回当前实例。

它是如何工作的? 当我们想要获取现有实例时,隐式同步方法很慢?还是实施了双锁?

3 个答案:

答案 0 :(得分:3)

Enum是线程安全的,并且the recommended way也可以实现Singleton。

那就是说,枚举并不是懒惰的。如果你想要一个延迟加载的单例,你可以使用Holder pattern(也是线程安全的):

class LazySingleton {

    private LazySingleton() {}

    private static class SingletonHelper{
        private static final LazySingleton INSTANCE = new LazySingleton();
    }

    public static LazySingleton getInstance(){
        return SingletonHelper.INSTANCE;
    }
}

答案 1 :(得分:1)

enum没有延迟初始化。它只会在加载类时创建实例。

  

当我们将单例实现为枚举时,将首次创建单例实例。

只有通过“第一次使用”,你才真正意味着“当班级被加载”时才会出现这种情况。

换句话说,使用您的示例,枚举将等同于:

private static final Singleton instance = new Singleton();

public static Singleton getInstance() {
    return instance;
}

答案 2 :(得分:1)

enum常量的初始化发生在类初始化程序中,类似于你编写的

static final Singleton instance = new Singleton();

static final Singleton instance;
static {
    instance = new Singleton();
}

安全来自the JVM perform class initialization under a JVM specific lock

这一事实
  

由于Java编程语言是多线程的,因此初始化类或接口需要仔细同步,因为其他一些线程可能正在尝试同时初始化同一个类或接口。 ... Java虚拟机的实现负责通过使用以下过程来处理同步和递归初始化。

     

...

     

对于每个类或接口C,都有一个唯一的初始化锁LC。从CLC的映射由Java虚拟机实现决定。

     

...

我从规范中遗漏了很多技术细节,对于Java程序员来说,最重要的一点是每个符合JVM的实现都有一个安全机制。该部分的结尾有注释:

  

实现可以通过在步骤1中删除锁获取(并在步骤4/5中释放)来优化此过程,此时它可以确定类的初始化已经完成,前提是,就记忆模型,所有发生的 - 在获得锁定时存在的排序,在执行优化时仍然存在。

当然,这是单例模式实现的一个重点,以后访问static final字段不需要获取锁。由于所有类都从未初始化状态到初始化状态只有一次,并且它影响每个操作(包括实现单例模式的所有其他可能性),因此您可以期望每个JVM都执行此基本优化。即使特定的JVM不这样做,static final字段也是该虚拟机上最快的懒惰单例实现...