8

我遇到了一些代码,其中开发人员不断检查单例是否为 null 两次,其中嵌套了 if - 如下代码所示:

private static processManager singleton = null;

...

public synchronized static processManager getInsatnce() throws Exception {

    if(singleton == null) {
      if(singleton == null){
             singleton = new processManager();
       }
     }
     return singleton
}

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

4

5 回答 5

16

您的代码没有正确演示案例。这源于双重检查的成语,它确实有意义:

// 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; }
于 2013-03-19T11:48:43.857 回答
6

这是实现Double Checked Locking Idiom的失败尝试。第一个null检查是查看实例是否已创建,如果已创建,则not null返回已创建的实例。

但是条件检查是一种检查然后执行的情况,并且不是线程安全的,因此有可能两个或多个线程将看到该值null并创建两个单例实例,或ManyTon 。

所以我们使用synchronized这样只有一个线程进入该块并且只创建一个实例。

于 2013-03-19T11:54:28.660 回答
3

我认为您指的是Double Checked Locking。此模式允许您在不需要时避免同步。

你的代码应该是

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.

在您的情况下,方法是同步的,您是对的。检查两次是没有意义的。

于 2013-03-19T11:51:54.653 回答
0

该技术称为双重检查。

但是,您粘贴的代码不正确。你是对的,以这种方式仔细检查空值是没有意义的。我会说双重检查的正确实施如下:

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() 方法是静态方法。

于 2013-03-19T11:58:59.747 回答
0

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

于 2013-03-19T11:49:50.660 回答