【问题标题】:Lazily initialising static variables in a multi-threaded situation在多线程情况下延迟初始化静态变量
【发布时间】:2014-11-25 11:47:23
【问题描述】:

我正在尝试编写一个实例方法来延迟初始化几个静态变量。我正在初始化的对象是不可变的,并且对象的引用不会被类中的任何其他实例或静态方法更改。我希望初始化代码永远不会被执行超过一次,即使在许多不同的线程中可能有该类的多个实例。初始化需要在实例方法中进行,因为该方法会覆盖超类中的方法。我使用的方法如下。

private static volatile boolean isPrepared;
private static volatile Object object1;
private static volatile Object object2;
private static volatile Object object3;

@Override
void prepare() {
    synchronized (this.getClass()) {
        if (isPrepared) { return; }
        object1 = expensiveCalculation1();
        object2 = expensiveCalculation2();
        object3 = expensiveCalculation3();
        isPrepared = true;
    }   
}

我假设由于初始化发生在单个同步块中,因此实例不可能将isPrepared 视为true,除非object1object2object3 都是非空。我还假设它不会通过简单地将prepare() 声明为synchronized 来工作,因为锁只是this。我的假设正确吗?另外,当您希望将多个变量标记为volatile 时将它们视为一起初始化,或者我应该将它们捆绑到一个不可变类中,这是一个好主意吗?

【问题讨论】:

    标签: java synchronized volatile static-variables


    【解决方案1】:

    将所有延迟初始化的状态捆绑到一个不可变对象中通常是首选方法,因为您需要的 all 是一个 volatile 变量,没有同步。如果另一个线程在初始化过程中开始初始化,那么这种安排会让您面临一些重复的工作,但这种可能性可以最小化,例如通过将标记值写入volatile 以表示“正在进行”状态。

    【讨论】:

    • 感谢您的回答。我想我会使用将变量捆绑到单个 volatile 变量中的方法。但是,volatile 和 synchronized 块的组合不是完全消除您提到的重复可能性的最简单方法吗?
    • 是的。首先检查 volatile var 的值,然后根据需要输入同步块。
    • 好点。如果 var 已经存在,您将不想等待其他线程。您是否必须两次检查 volatile var 的值,一次是查看是否需要同步块,一次是在块的开头?由于初始检查未同步,因此在您进入同步块时,初始化可能已在另一个线程中完成。
    • 是的,这正是正确的双重检查习语在 Java 中的样子。查看对 Josh Bloch 的采访,看看这个成语和另一个,它提供了更多的便利(持有人类)。 oracle.com/technetwork/articles/java/…
    【解决方案2】:

    您可以使用下一个方法:https://stackoverflow.com/a/11879164/2413618 将变量放入静态嵌套类中。当嵌套类第一次被访问时,所有的变量都会被初始化。

    【讨论】:

      猜你喜欢
      • 2011-11-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多