Java如何确保在JVM中只有一个枚举实例

11

Java是如何内部保证每个JVM只存在一个ENUM实例的?它是在应用程序启动时创建的,并且从那时起,当多个线程访问它时,它将返回在启动时创建的对象吗?


还是它实现了一种类似于单例模式的双重同步,以便即使多个线程访问它,也只会创建一个实例?


1
它确保每个类加载器只有一个实例。如果你有多个类加载器,每个类加载器都可以拥有自己的实例。它们是按需创建的。(懒加载)JVM 为此拥有自己的互斥锁。 - Peter Lawrey
2个回答

7

正如您可以在这个答案中所读到的那样,枚举实例是静态类字段,因此在第一次访问该类时作为类加载的一部分进行初始化。

类加载是内部同步的,这确保了枚举实例是单例(即在同一类加载器中是单例。如果您有多个加载器加载相同的枚举,则会获得多个实例)。


谢谢。普通静态变量也是如此吗?即静态变量是否会因多个类加载器而被多次初始化而存在危险? - Victor
1
@Victor - 是的。在普通的Java程序中你看不到这个问题,但在更复杂的系统如J2EE中,有多个类加载器时,这是一个常见的问题。 - radai
@Victor 静态初始化是在类加载器的上下文中执行的。如果有多个类加载器(例如在J2EE中隔离),只要这些类加载器被隔离并且不在其层次结构的任何级别汇聚,它们将被多次加载(因为请求加载会意味着返回一个常见父类加载器缓存中的内容)。 - Fritz
如果所讨论的类在类加载器树中的多个JAR文件中被找到,这种情况很常见,特别是当某人将库包含在部署特定的/lib目录和一些更高级别的全局/lib目录中时。即使这些类加载器不完全分离,也可能发生这种情况。 - radai
@radai 我在讨论正常的行为,如果开发人员选择部署 fat WARs,那就是另一个问题的讨论 :). 不过,你说得对,但这不会与类加载本身有关,而是人为错误导致的。 - Fritz

3

枚举实例在类加载时创建。如果同一个枚举类被多个类加载器加载(例如,在Web应用程序容器中进行类加载游戏时),您将在内存中拥有多个不兼容的实例。


“不兼容实例”是什么意思? - apersiankite
这意味着实例看起来相同,但测试: enum1.getClass() == enum2.getClass() 返回 false。它们实际上是JVM中不同的类。 - Michał Zabielski

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接