为什么枚举单例是懒惰的? [英] Why enum singleton is lazy?

查看:253
本文介绍了为什么枚举单例是懒惰的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我看到了类似的答案,试图通过评论,并且对此此处的示例不满意。


也许是时候回答这个特定问题了……


为什么枚举单例实现被称为 lazy


< pre class = lang-java prettyprint-override> 公共枚举EnumLazySingleton {
INSTANCE;
EnumLazySingleton(){
System.out.println( constructing:" + this);
}
public static void touchClass(){}
}

它是怎么回事与渴望实现不同吗?

 公共类BasicEagerSingleton {
private static final BasicEagerSingleton实例= new BasicEagerSingleton();
public static BasicEagerSingleton getInstance(){
返回实例;
}
private BasicEagerSingleton(){
System.out.println( constructing:" + this);
}
public static void touchClass(){}
}

两者都会初始化实例而不访问 INSTANCE / getInstance()-例如调用 touchClass()

 公共类TestSingleton {
public static void main(String ... args){
System.out.println(睡眠5秒...);
System.out.println( touching + BasicEagerSingleton.class.getSimpleName());
BasicEagerSingleton.touchClass();
System.out.println( touching + EnumLazySingleton.class.getSimpleName());
EnumLazySingleton.touchClass();
}
}

输出:

 睡眠5秒钟... 
接触BasicEagerSingleton
构造:BasicEagerSingleton @ 7bfcd12c
接触EnumLazySingleton
构造:立即实例

现在,我们可以说两者都是惰性。那么渴望是什么?


很明显如何(例如)双重检查锁定?方式实际上是懒惰的(又杂乱又缓慢)。但是,如果枚举是惰性的,则由于不可避免的类加载,任何单例都是惰性的-实际上,所有事物都是惰性的。

解决方案

前两个链接的答案(由 Peter Lawrey em>和 Joachim Sauer )都同意枚举未初始化。第三个链接中的答案完全是关于延迟初始化的含义的。


使用枚举作为单例的建议源自Josh Bloch的Effective Java。值得注意的是,有关枚举单例的这一章没有提及懒惰。后面的章节专门介绍延迟初始化,同样也没有提及枚举。本章包含两个重点。



  • 如果您需要在静态字段上使用惰性初始化来提高性能,请使用惰性初始化持有人类习惯用法。

  • 如果您需要使用延迟初始化来提高实例字段的性能,请使用仔细检查的习语。


毫无疑问,枚举如果以某种方式延迟初始化它们,则它将是此列表上的另一个惯用法。实际上,事实并非如此,尽管如操作说明所示,对延迟初始化含义的混淆会导致一些错误的答案。


I saw answers like these, tried to clarify via comments, and was unsatisfied by examples here.

Maybe it's time for this specific question...

Why enum singleton implementation is called lazy?

public enum EnumLazySingleton {
    INSTANCE;
    EnumLazySingleton() {
        System.out.println("constructing: " + this);
    }
    public static void touchClass() {}
}

How it is different from eager implementation?

public class BasicEagerSingleton {
    private static final BasicEagerSingleton instance = new BasicEagerSingleton();
    public static BasicEagerSingleton getInstance() {
        return instance;
    }
    private BasicEagerSingleton() {
        System.out.println("constructing: " + this);
    }
    public static void touchClass() {}
}

Both will init instance without accessing INSTANCE/getInstance() - e.g. call touchClass().

public class TestSingleton {
    public static void main(String... args) {
        System.out.println("sleeping for 5 sec...");
        System.out.println("touching " + BasicEagerSingleton.class.getSimpleName());
        BasicEagerSingleton.touchClass();
        System.out.println("touching " + EnumLazySingleton.class.getSimpleName());
        EnumLazySingleton.touchClass();
    }
}

Output:

sleeping for 5 sec...
touching BasicEagerSingleton
constructing: BasicEagerSingleton@7bfcd12c
touching EnumLazySingleton
constructing: INSTANCE

Now, we can say both are lazy. What is eager then?

It is clear how (e.g) "double-checked locking" way is actually lazy (and messy, and slow). But if enum is lazy, then any singleton is lazy due to inevitable class loading - in fact, everything is lazy. At which point will this distinction stop making any sense?

解决方案

The first two linked answers (by Peter Lawrey and Joachim Sauer) both agree that enums are not lazily initialized. Answers in the third link are simply wrong about what lazy initialization means.

The recommendation to use enums as singletons originates from Josh Bloch's Effective Java. Notably, the chapter on enum singletons makes no mention of laziness. There is a later chapter dedicated to lazy initialization, that likewise makes no mention of enums. The chapter contains two highlights.

  • If you need to use lazy initialization for performance on a static field, use the lazy initialization holder class idiom.
  • If you need to use lazy initialization for performance on an instance field, use the double-check idiom.

Undoubtedly, enums would be another idiom on this list if they were in any way lazily initialized. In fact they are not, although confusion about the meaning of lazy initialization results in some incorrect answers, as the OP shows.

这篇关于为什么枚举单例是懒惰的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆