Java - 是否有任何理由检查单例是否为空?

问题描述:

我所遇到的一些代码,其中开发人员不断使用嵌套的,如果检查,如果单是空的两倍 - 就像下面的代码:Java - 是否有任何理由检查单例是否为空?

private static processManager singleton = null; 

...

public synchronized static processManager getInsatnce() throws Exception { 

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

我看不出有什么理由可以这样做,但代码中有很多实例,所以认为可能有一个原因?

+6

它看起来像一个失败的尝试在两阶段锁定。如果最里面的'if'语句位于'synchronized'块中,那么这可能是有意义的。 – toniedzwiedz 2013-03-19 11:49:28

+0

是的,我在看Marko的答案。有趣! – Sanchit 2013-03-19 11:49:49

+0

http://en.wikipedia.org/wiki/Double-checked_locking? – mbatchkarov 2013-03-19 11:50:04

您的代码没有正确显示该情况。这源于双重检查成语,它有一定道理:

// 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; 
} 

读到它over here

请注意,该成语仅适用于实例字段。在你的问题,你有一个static领域,这种情况下,一个更简单的成语是首要选择:懒initialion holder类成语:

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

此不作任何SENCE,除非单是财产在getter中创建实例,但即使这样做也没有意义,那么其余代码将无法访问。

我想你是指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; 
} 

所以你看,我们只同步时,我们已经检查了单不为空,那么,我们重新检查,以防万一有人已经开始建立它。不是说这个工作单身人士必须是volatileHere是一篇文章,解释如果您忘记volatile时出现的细微问题。

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

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

但条件检查是检查当时的行为情况,是不是线程安全的,所以有可能是两个或更多的线程将看到价值null创造的两个实例那就是doubleton或者ManyTon

因此,我们使用​​,以便只有一个线程进入该块,并且只创建一个实例。

+0

双重检查锁定成语的优秀解释。 – Deepak 2013-03-19 12:06:48

+0

因为这个方法是同步的,所以大概不需要使用双重检查锁定? – 2013-03-19 12:14:24

+0

保持方法singleton在关系之前创建一个发生,因此只有一个空检查是可以的。注意:此方法执行不好,因为它锁定了类。所以最好不要让方法保持同步,而是使用其他答案中已经提到的技术。 – 2013-03-19 18:23:48

该技术被称为双重检查。

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

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

+1

除非实例是易失性的,否则这看起来很糟糕 - 实例“if(instance == null)”的第一次读取未同步。 – assylias 2013-03-19 12:08:49

+0

是的,你是对的。 – 2013-03-19 12:15:29