Findbug告诉我,我使用了不正确的延迟初始化。
public static Object getInstance() {
if (instance != null) {
return instance;
}
instance = new Object();
return instance;
}
我在这里看不出任何错误。这是findbug的错误行为,还是我错过了什么?
答案 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()