Java 不正确的延迟初始化
Findbug告诉我使用了不正确的延迟初始化Java 不正确的延迟初始化,java,findbugs,Java,Findbugs,Findbug告诉我使用了不正确的延迟初始化 public static Object getInstance() { if (instance != null) { return instance; } instance = new Object(); return instance; } 我看这里没有什么问题。是findbug的错误行为,还是我遗漏了什么?findbug引用了一个潜在的线程问题。在多线程环境中,可能会使用当前代码多次创建单例
public static Object getInstance() {
if (instance != null) {
return instance;
}
instance = new Object();
return instance;
}
我看这里没有什么问题。是findbug的错误行为,还是我遗漏了什么?findbug引用了一个潜在的线程问题。在多线程环境中,可能会使用当前代码多次创建单例 有很多阅读材料,但这有助于解释
此处的竞态条件在
if check
上。在第一次调用时,线程将进入if check
,并将创建实例并将其分配给“instance”。但是在if检查和实例创建/分配之间,另一个线程可能会变为活动线程。此线程还可以通过检查,因为分配尚未发生。因此,将创建两个(或更多,如果有更多线程进入)实例,并且您的线程将具有对不同对象的引用。您的代码比需要的稍微复杂一些,这可能就是为什么会混淆的原因
编辑:这肯定是线程问题,正如其他人发布的一样,但我认为我应该在这里发布双锁检查实现,以供参考:
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;
}
您需要在实例化周围加上一个锁,以使其正确
LI:静态字段的延迟初始化不正确
(LI_LAZY_INIT_STATIC)
此方法包含对
非易失性静电场。因为编译器或处理器可能
重新排序指令时,线程不能保证看到完整的
初始化对象,如果该方法可由多个线程调用。
您可以使字段不稳定以更正问题。更多
有关详细信息,请参阅Java内存模型网站
您的静态对象未同步。此外,您的方法不是惰性初始化。通常,您要做的是保留对象的映射,并根据需要初始化所需的映射。因此,您不会在一开始就初始化所有的锁,而不是在需要时调用它们(调用)。注意:Johnkehm的双锁检查解决方案更好。出于历史原因,将这个答案留在这里
事实上应该是这样
public synchronized static Object getInstance() {
if (instance == null) {
instance = new Object();
}
return instance;
}
感谢John Klehm提供的样品
也可以尝试直接在同步块中分配对象实例
synchronized (MyCurrentClass.myLock=new Object())
i、 e
您错过了多线程问题
private static Object instance;
public static synchronized Object getInstance() {
return (instance != null ? instance : (instance = new Object()));
}
因为1.5:实例应该是可变的,您应该集成一个tmp变量,以避免使用已创建但其初始化尚未完成的实例
private static volatile Object myLock = new Object();
private static volatile Object instance;
public static Object getInstance() {
if (instance == null) {
Object tmpObj;
synchronized (myLock) {
tmpObj = instance;
if (tmpObj == null) {
tmpObj = new Object();
}
}
instance = tmpObj;
}
return instance;
}
如果(instance==null)instance=newobject(),它可能需要;返回实例
?@Matt:这是一种惰性初始化,只有在类的所有构造函数都是私有的情况下,它才会生成一个单例。是的,它确实希望模式是:```if(instance==null){instance=new Object();}return instance```使方法同步化
将是解决此问题的最简单方法。@约翰:正确,在这种情况下,这几乎总是最好的解决方案。仅使其同步将导致每次调用的同步开销;您只需要在第一次调用时使用它。@antlersoft,但实际上您甚至不需要在非线程应用程序上使用它。多重实例化只是一种可能性。更糟糕的是,编译器可能会对指令重新排序,调用方可能会有一个部分构造对象的实例,该实例具有默认值。这真的比使整个方法同步并只执行一次测试有所改进吗?我一直被告知同步比if检查更昂贵。我从来没有亲自测量过它。请阅读此处,了解如何进行双重锁检查的详细讨论(它比应该的更棘手):要使其正常工作,您的锁必须是易失性的
。我知道您已经说明了这一点,但我认为您应该在回答中更明确一点。将变量myLock
声明为volatile
没有帮助。相反,您必须将变量实例
声明为volatile
。我更喜欢这段代码,而不是它最初的样子,但这并不能解释为什么原始代码是错误的。在发布时,其中一个答案已经提到了多线程环境中非同步延迟实例化的不良影响。我只是把它写成代码。:)不过,这仍然不能解决违规问题。啊-现在已经同步了。我错过了(或者它被改变了)。使用synchronized,它确实解决了问题:)
private static volatile Object myLock = new Object();
private static volatile Object instance;
public static Object getInstance() {
if (instance == null) {
Object tmpObj;
synchronized (myLock) {
tmpObj = instance;
if (tmpObj == null) {
tmpObj = new Object();
}
}
instance = tmpObj;
}
return instance;
}