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
}
我看不出有什么理由可以这样做,但代码中有很多实例,所以认为可能有一个原因?
您的代码没有正确显示该情况。这源于双重检查成语,它有一定道理:
// 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;
}
所以你看,我们只同步时,我们已经检查了单不为空,那么,我们重新检查,以防万一有人已经开始建立它。不是说这个工作单身人士必须是volatile
。 Here是一篇文章,解释如果您忘记volatile
时出现的细微问题。
在你的情况下,方法是同步的,你是对的。检查两次没有意义。
这是一个失败的尝试实现Double Checked Locking Idiom。第一个null
检查是查看实例是否已经创建,如果是not null
,则只返回已创建的实例。
但条件检查是检查当时的行为情况,是不是线程安全的,所以有可能是两个或更多的线程将看到价值null
创造单的两个实例那就是doubleton或者ManyTon。
因此,我们使用,以便只有一个线程进入该块,并且只创建一个实例。
双重检查锁定成语的优秀解释。 – Deepak 2013-03-19 12:06:48
因为这个方法是同步的,所以大概不需要使用双重检查锁定? – 2013-03-19 12:14:24
保持方法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()方法是一个静态方法。
除非实例是易失性的,否则这看起来很糟糕 - 实例“if(instance == null)”的第一次读取未同步。 – assylias 2013-03-19 12:08:49
是的,你是对的。 – 2013-03-19 12:15:29
它看起来像一个失败的尝试在两阶段锁定。如果最里面的'if'语句位于'synchronized'块中,那么这可能是有意义的。 – toniedzwiedz 2013-03-19 11:49:28
是的,我在看Marko的答案。有趣! – Sanchit 2013-03-19 11:49:49
http://en.wikipedia.org/wiki/Double-checked_locking? – mbatchkarov 2013-03-19 11:50:04