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

我有一个关于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...
}
  • 现在是否存在这样一种场景:由于垃圾收集器的原因,initialized可能会恢复为FALSE?我之所以这么问,是因为如果是这样的话,我需要对这种情况采取额外的预防措施

  • 而且,如果我用一个枚举来表示en singleton,那么对于state使用静态变量还是非静态变量会有什么影响?例如,在这个例子中,有两个变量;someVar和initialized,如果initialized也是静态的,那么问题1会有所不同吗?或者如果两者都是非静态的

    谢谢


  • 枚举类型上不应进行垃圾收集。您的
    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...
        }
    }