2014-11-25 24 views
1

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

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; 
    } 
} 

我假设从初始化发生在一个synchronized块,那将是不可能的实例来不断观察isPreparedtrue除非object1object2object3都是非空。我还假设它不会工作,只需声明prepare()为​​锁定为this。我的假设是正确的吗?另外,当你想将它们视为一起初始化时,是否有一个标记为volatile的变量是一个好主意,还是应该将它们组合成一个Immutable类?

回答

1

捆绑所有延迟初始化状态进入一个不可变的对象通常是优选的方法,因为然后你需要所有volatile变量,没有同步。如果另一个线程在初始化过程中开始初始化,那么这种安排可以为您带来一些重复的努力,但是可以最小化这种机会,例如通过将标记值写入volatile来表示“进行中”状态。

+1

感谢您的回答。我想我会使用将变量绑定到单个易变变量的方法。但是,是不是volatile和synchronized block的组合是完全消除你提到的重复的可能性的最简单方法? – 2014-11-25 12:40:09

+1

是的。首先检查volatile var的值,然后根据需要输入synchronized块。 – 2014-11-25 12:49:35

+0

好点。如果var已经存在,你不想等待其他线程。您是否需要检查volatile var的值两次,一次查看是否需要同步块,以及一次是否在块的开头?由于初始检查不同步,因此在进入同步块时,初始化可能已在另一个线程中完成。 – 2014-11-25 13:00:46