Java -是否有任何理由检查一个单例是否为空两次



我遇到过一些代码,其中开发人员不断检查单例是否为空两次,嵌套的if -类似于下面的代码:

private static processManager singleton = null;

public synchronized static processManager getInsatnce() throws Exception {
    if(singleton == null) {
      if(singleton == null){
             singleton = new processManager();
       }
     }
     return singleton
}

我看不出这可能是什么原因,但是代码中有很多实例,所以认为可能有原因?

您的代码没有正确地演示这种情况。这源于反复检查的习惯用法,在这里它是有意义的:

// Double-check idiom for lazy initialization of instance fields.
private volatile FieldType field;
FieldType getField() {
    FieldType result = field;
    if (result == null) { // First check (no locking)
        synchronized(this) {
            result = field;
            if (result == null) // Second check (with locking)
                field = result = computeFieldValue();
        }
    }
    return result;
}

看这里

请注意,这种习惯用法仅适用于实例字段。在您的问题中,您有一个static字段,在这种情况下,一个更简单的习惯用法是主要选择:惰性初始化持有人类习惯用法:

// Lazy initialization holder class idiom for static fields
private static class FieldHolder {
    static final FieldType field = computeFieldValue();
}
static FieldType getField() { return FieldHolder.field; }

这是实现双重检查锁定习惯用法的失败尝试。第一个null检查是查看实例是否已经创建,如果是not null,则返回已经创建的实例。

但是条件检查是检查-处理情况,并且不是线程安全的,因此有可能两个或多个线程将看到值为null并创建两个单例双例ManyTon实例。

所以我们使用synchronized,所以只有一个线程进入该块,只有一个实例被创建。

我想你指的是双重检查锁定。此模式允许您在不需要同步时避免同步。

你的代码应该是
private static volatile ProcessManager singleton = null;
public static ProcessManager getInstance() throws Exception {
    if (singleton == null) {
        synchronized (MyClass.class) {
            if (singleton == null) {
                singleton = new ProcessManager();
            }
        }
    }
    return singleton;
}

所以你看,我们只同步当我们已经检查了单例不为空,然后我们重新检查,以防有人已经开始构建它。注意,要使其工作,单例必须是 volatile。这里有一篇文章,解释了如果您忘记volatile,会出现的微妙问题。

在你的例子中,方法是同步的,你是对的。检查两次是没有意义的。

除非单例是在getter中创建实例的属性,否则这没有任何意义,但即使这样,这也没有意义,否则其余的代码将无法访问。

这种技术叫做双重检查。

但是,您粘贴的代码是不正确的。你是对的,以这种方式检查空值是没有意义的。我想说双重检查的正确实现如下:
private static volatile ProcessManager instance = null;
public static ProcessManager getInstance() {
   if (instance == null) {
       synchronized(ProcessManager.class) {
         if (instance == null) {
            instance = new ProcessManager();
         }
      }
   }
   return instance;
}

注意,第二个空检查是在ProcessManager.class对象上同步的。这是必要的,因为getInstance()方法是静态的。

最新更新