延迟初始化不正确

时间:2011-07-21 20:54:31

标签: java findbugs

Findbug告诉我,我使用了不正确的延迟初始化。

public static Object getInstance() {
    if (instance != null) {
        return instance;
    }

    instance = new Object();
    return instance;
}

我在这里看不出任何错误。这是findbug的错误行为,还是我错过了什么?

8 个答案:

答案 0 :(得分:60)

Findbug引用潜在的线程问题。在多线程环境中,使用当前代码可能会多次创建单例。

有很多阅读here,但这有助于解释。

这里的竞争条件是if check。在第一次调用时,线程将进入if check,并将创建实例并将其分配给“实例”。但是另一个线程有可能在if check和实例创建/赋值之间变为活动状态。此线程也可以传递if check,因为分配尚未发生。因此,将创建两个(或更多,如果有更多线程进入)实例,并且您的线程将引用不同的对象。

答案 1 :(得分:18)

您的代码比需要的稍微复杂一些,这可能是它混淆的原因。

编辑:这绝对是其他人发布的线程问题,但我认为我会在这里发布双锁检查实现,以供参考:

private static final Object lock = new Object();
private static volatile Object instance; // must be declared volatile

public static Object getInstance() {
    if (instance == null) { // avoid sync penalty if we can
        synchronized (lock) { // declare a private static Object to use for mutex
            if (instance == null) {  // have to do this inside the sync
                instance = new Object();
            }
        }
    }

    return instance;
}

答案 2 :(得分:11)

注意:JohnKlehm的双锁检查解决方案更好。出于历史原因,在此留下这个答案。

它应该是

public synchronized static Object getInstance() {
    if (instance == null) {
        instance = new Object();
    }

    return instance;
}

答案 3 :(得分:4)

您需要锁定实例化以使其正确

  

LI:静态字段的延迟初始化不正确   (LI_LAZY_INIT_STATIC)

     

此方法包含a的非同步延迟初始化   非易失性静电场。因为编译器或处理器可能   重新排序说明,线程不保证完全看到   初始化对象,如果该方法可以被多个线程调用。   您可以使字段为volatile以纠正问题。更多   有关信息,请参阅Java Memory Model网站。

答案 4 :(得分:2)

感谢John Klehm发布的样本

也可以尝试直接在sychronised block中分配对象实例

synchronized (MyCurrentClass.myLock=new Object())

private static volatile Object myLock = new Object();

public static Object getInstance() {
    if (instance == null) { // avoid sync penalty if we can
        synchronized (MyCurrentClass.myLock**=new Object()**) { // declare a private static Object to use for mutex
            if (instance == null) {  // have to do this inside the sync
                instance = new Object();
            }
        }
    }

    return instance;

}

答案 5 :(得分:2)

您错过了多线程问题,

int* a = new int;
delete a;
delete a; // same as your code

答案 6 :(得分:0)

您的静态对象未同步。而且你的方法不是一个懒惰的初始化。通常,您所做的是保留对象的Map,并根据需要初始化所需的对象。因此,您不要在开始时初始化所有这些,而不是在需要时调用它们(称为)。

答案 7 :(得分:0)

从1.5开始:实例应该是volatile,并且你要集成一个tmp变量,以避免使用创建的实例,但是它的初始化还没有完成。

ip_format()