我遇到过一些代码,开发人员不断检查单例是否为嵌套if的两次 - 如下面的代码所示:
private static processManager singleton = null;
...
public synchronized static processManager getInsatnce() throws Exception {
if(singleton == null) {
if(singleton == null){
singleton = new processManager();
}
}
return singleton
}
我看不出这可能是什么原因,但代码中有很多实例,所以认为可能有原因?
答案 0 :(得分:15)
您的代码无法正确演示案例。这源于双重检查的习语,它确实有意义:
// 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
字段,在这种情况下,一个更简单的习语是主要选择: lazy initialion holder class idiom:
// Lazy initialization holder class idiom for static fields
private static class FieldHolder {
static final FieldType field = computeFieldValue();
}
static FieldType getField() { return FieldHolder.field; }
答案 1 :(得分:4)
尝试实现Double Checked Locking Idiom失败了。第一个null
检查是查看实例是否已经创建,如果它是not null
,那么只返回已经创建的实例。
但是条件检查是一个 check-then-act 情况并且不是线程安全的,所以有两个或更多线程可能会将值视为null
并创建 singleton 的两个实例,然后创建 doubleton 或者 ManyTon 。
所以我们使用synchronized
,这样只有一个线程进入该块,只创建一个实例。
答案 2 :(得分:2)
我认为你指的是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
时出现的微妙问题。
在你的情况下,方法同步,你是对的。检查两次是没有意义的。
答案 3 :(得分:0)
除非单例是在getter中创建实例的属性,否则这不会产生任何意义,但即便如此,这也没有意义,因此其余的代码将无法访问。
答案 4 :(得分: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()方法是静态方法。