Java枚举垃圾收集&;枚举变量差异
我有一个关于java垃圾收集和枚举类型的问题。 假设我有这样一个枚举:Java枚举垃圾收集&;枚举变量差异,java,enums,garbage-collection,Java,Enums,Garbage Collection,我有一个关于java垃圾收集和枚举类型的问题。 假设我有这样一个枚举: enum ConnectionHelper { INSTANCE; private boolean initialized = false; private static int someVar; ConnectionHelper initialize() { if (!initialized) { // Do some initialisation... someVar = 1
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...
}
枚举类型上不应进行垃圾收集。您的
ConnectionHelper.INSTANCE
无法取消引用,因此一旦实例化,对象将始终保留在内存中
所以,对于你的问题:
广告1:不,它不能恢复。将其设置回false
的唯一方法是手动设置
广告2:单身汉没有区别。如果您有更多的实例,则会有所不同,因为它们将共享
静态
变量,而不是通常的变量。枚举类型上不需要垃圾收集。您的ConnectionHelper.INSTANCE
无法取消引用,因此一旦实例化,对象将始终保留在内存中
所以,对于你的问题:
广告1:不,它不能恢复。将其设置回false
的唯一方法是手动设置
广告2:单身汉没有区别。如果你有更多的实例,情况会有所不同,因为它们将共享
静态变量,而不是通常的变量。我们可以回答所有类型的“垃圾收集器是否会使这个程序行为异常”的问题,通常是“否”。垃圾收集器的目的就是透明地清理未使用对象的内存,而程序甚至不会注意到。产生一个可观察的行为,比如一个变量从true
翻转到false
,这显然超出了垃圾收集器允许的操作范围
也就是说,您的程序不是线程安全的。如果多个线程访问您的ConnectionHelper
而不进行额外同步,则它们可能会感知到不一致的结果,包括看到初始化的变量的false
,而从外部时钟的角度看,另一个线程在更早的时候已经看到它的true
,或者查看初始化的的true
,但仍然没有看到为someVar
编写的10
的值
解决办法很简单。不要实现多余的惰性初始化。enum
常量是在类初始化期间初始化的,类初始化已经是惰性的(如中所指定),并且JVM使其成为线程安全的(如中所指定)
enum ConnectionHelper {
INSTANCE;
private static final int someVar = 10;
void start() {
// do some work, use the already initialized someVar...
}
}
或
或
无论您是否声明变量static
第一个调用start()
的线程将执行类初始化,包括someVar
的初始化。如果其他线程在初始化仍在进行时调用该方法,它们将等待其完成。初始化完成后,所有线程都可以使用初始化值执行start()
方法,而不会减慢速度。我们可以回答所有类型的“垃圾收集器是否会使此程序异常运行”问题,通常是“否”。垃圾收集器的目的就是透明地清理未使用对象的内存,而程序甚至不会注意到。产生一个可观察的行为,比如一个变量从true
翻转到false
,这显然超出了垃圾收集器允许的操作范围
也就是说,您的程序不是线程安全的。如果多个线程访问您的ConnectionHelper
而不进行额外同步,则它们可能会感知到不一致的结果,包括看到初始化的变量的false
,而从外部时钟的角度看,另一个线程在更早的时候已经看到它的true
,或者查看初始化的的true
,但仍然没有看到为someVar
编写的10
的值
解决办法很简单。不要实现多余的惰性初始化。enum
常量是在类初始化期间初始化的,类初始化已经是惰性的(如中所指定),并且JVM使其成为线程安全的(如中所指定)
enum ConnectionHelper {
INSTANCE;
private static final int someVar = 10;
void start() {
// do some work, use the already initialized someVar...
}
}
或
或
无论您是否声明变量static
第一个调用start()
的线程将执行类初始化,包括someVar
的初始化。如果其他线程在初始化仍在进行时调用该方法,它们将等待其完成。初始化完成后,所有线程都可以执行start()
方法使用初始化值而不会减速。实例
不能被垃圾收集,因为ConnectionHelper
有一个引用。实例
不能被垃圾收集,因为ConnectionHelper
有一个引用。如果调用ConnectionHelper.INSTANCE.start()它会被扔掉的,我的错。出于某种原因,我认为initialize()
是构造函数,而不是简单的方法。如果调用ConnectionHelper.INSTANCE.start(),它将被抛出。我的错误。出于某种原因,我认为initialize()
是构造函数,而不是一个简单的方法。感谢您详细的回答。但是,例如,如果您有一个带有静态变量(非final)的类,该变量在字段中被修改。我见过android的例子,其中内存使用被强制到内存不足的情况,其中t
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...
}
}