延迟初始化不正确

mic*_*nko 53 java findbugs

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

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

    instance = new Object();
    return instance;
}
Run Code Online (Sandbox Code Playgroud)

我没有看到任何错误.这是findbug的错误行为,还是我错过了什么?

nic*_*ild 60

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

有大量的阅读在这里,但它会有助于解释.

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

  • 使方法"同步"将是解决这个问题的最简单方法. (16认同)
  • 只是使它同步将导致每次调用的同步开销; 你只需要第一次通话. (5认同)

Joh*_*ehm 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;
}
Run Code Online (Sandbox Code Playgroud)

  • 将变量`myLock`声明为`volatile`没有用处.相反,您必须将变量`instance`声明为`volatile`. (3认同)
  • 我总是被告知同步比if检查更昂贵.我自己从未真正测量过它. (2认同)

Var*_*har 11

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

它应该是

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

    return instance;
}
Run Code Online (Sandbox Code Playgroud)