我对Java垃圾回收和枚举类型有疑问。 可以说我有一个这样的枚举:
enum ConnectionHelper {
INSTANCE;
private boolean initialized = false;
private static int someVar;
ConnectionHelper initialize() {
if (!initialized) {
// Do some initialisation...
someVar = 10;
// NOTE: 1
initialized = true;
}
return this;
}
void start() {
// NOTE: 2
if (!initialized) {
throw new IllegalStateException("ConnectionHelper has to be initialized.");
}
// do some work...
}
现在是否存在由于垃圾回收器而初始化为FALSE的情况?我要问的原因是,如果是这种情况,我需要针对这种情况采取其他预防措施。
而且,如果我用枚举表示en单身人士,那么我使用静态还是非静态变量表示状态是否重要?例如,在此示例中,有两个变量; someVar并已初始化,如果初始化也是静态的,那么对问题1会有影响吗?还是两者都不是静态的?
谢谢!
答案 0 :(得分:3)
通常,我们可以用“否”回答各种“垃圾回收器会使程序变得奇怪”的问题。垃圾收集器的主要目的是透明地清理未使用对象的内存,而程序甚至不会注意到。产生可观察到的行为,例如从true
到false
的变量翻转,绝对超出了垃圾收集器所允许的动作。
也就是说,您的程序不是线程安全的。如果多个线程在没有额外同步的情况下访问您的ConnectionHelper
,它们可能会感觉到不一致的结果,包括看到false
的{{1}}变量,而另一个线程早些时候已经看到了initialized
从外部时钟的角度看待时间,或者看到true
的{{1}},而仍然看不到为true
编写的initialized
的值。
解决方案很简单。不要执行多余的延迟初始化。 10
常量是在类初始化期间初始化的,该类已经被JVM延迟了(如JLS §12.4.1中所指定),并由JVM使线程安全(如JLS §12.4.2中所指定)。
someVar
或
enum
或
enum ConnectionHelper {
INSTANCE;
private static final int someVar = 10;
void start() {
// do some work, use the already initialized someVar...
}
}
是否声明变量enum ConnectionHelper {
INSTANCE;
private final int someVar = 10;
void start() {
// do some work, use the already initialized someVar...
}
}
都没有关系。
第一个调用enum ConnectionHelper {
INSTANCE;
private final int someVar;
ConnectionHelper() {
someVar = 10; // as place-holder for more complex initialization
}
void start() {
// do some work, use the already initialized someVar...
}
}
的线程将执行类初始化,包括static
的初始化。如果在初始化仍在进行时其他线程调用该方法,则它们将等待其完成。初始化完成后,所有线程都可以使用初始化后的值执行start()
方法,而不会降低速度。
答案 1 :(得分:1)
枚举类型不希望进行垃圾收集。您的ConnectionHelper.INSTANCE
无法取消引用,因此实例化后,该对象将始终保留在内存中。
所以,对你的问题:
AD 1:否,无法还原。将其重新设置为false
的唯一方法是手动设置。
AD 2:单身没有差异。如果您有更多实例,将会有所不同,因为它们将共享static
变量,而不是通常的变量。