1

这是我的代码目前的样子:

private boolean[] isInitialized = new boolean[COUNT];

private void ensureInitialized(int i) {
    if (! isInitialized[i]) {
        initialize(i);
        isInitialized[i] = true;
    }
}

现在我想让它线程安全。我知道Java中的双重检查锁定是“teh 3vilness!!1”,但由于ensureInitialized可能经常被调用,我不希望它被同步。所以我正在考虑这样做:

private boolean[] isInitialized = new boolean[COUNT];

private void ensureInitialized(int i) {
    if (! isInitialized[i]) {
        synchronized (this) {
            if (! isInitialized[i]) {
                initialize(i);
                isInitialized[i] = true;
            }
        }
    }
}

现在我该怎么做才能使这个真正的线程安全?
一些子问题:

  • 没有必要制作isInitializedvolatile,因为变量没有改变,对吧?
  • 数组元素发生了变化,我怎样才能让它们变得易变?
  • 通常有更好的方法来做到这一点吗?

(还要注意这是一个实例方法,所以静态初始化器将不起作用)

4

2 回答 2

3

您也可以考虑使用Suppliers.memoize(Supplier<T> delegate)from guava library

于 2011-01-25T22:04:38.723 回答
1

请注意,双重检查的 java 实现被称为“破坏模式”,因为它被证明是失败的(例如参见http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html)。要解决这个问题,只需使用原子操作。以下是如何构建线程安全单例的示例:

static AtomicReferenceArray<Boolean> instance = 
   new AtomicReferenceArray<Boolean>(COUNT);

private void ensure(int i)
{
    if(!instance.get(i) )
    {
        synchronized(this){
        if( !instance.get(i) ){
           initialize(i);
           instance.set(i, true);
        }
    }
}
于 2010-10-09T18:05:50.307 回答