我读了一篇blog,讨论了什么时候单例不是单例。
在作者试图解释的其中一种情况中,显示了双重检查锁定在Singleton上实现时也可能失败。
// Double-checked locking -- don't use
public static MySingleton getInstance() {
if (_instance==null) {
synchronized (MySingleton.class) {
if (_instance==null) {
_instance = new MySingleton();
}
}
}
}对于上面的代码块,作者说:
“在这种情况下,我们打算避免每次调用方法时获取单例类的锁的开销。只有当单例实例不存在时才会获取锁,然后再次检查实例的存在,以防另一个线程在当前线程之前的瞬间通过第一次检查。”
有人能帮我解释一下这到底是什么意思吗?
发布于 2013-06-30 09:28:45
我会试着把这件事说清楚。
synchronized块需要时间才能进入,因为它需要跨线程协调。如果需要,我们将尽量避免输入它。
现在,如果我们使用多个线程,如果对象已经存在,让我们只返回它,因为方法将在内部根据线程竞争条件进行同步。我们可以在进入同步块之前这样做,就好像它是被创建的,它是被创建的。构造函数已经设计好了,所以不能返回部分构造的对象,正如内存模型设计所指定的那样。
如果单例对象还不存在,我们需要创建一个。但是如果在我们检查的时候另一个线程创建了它呢?我们将使用synchronized来确保没有其他线程持有它。现在,一旦我们进入,我们再检查一次。如果单例是由另一个线程创建的,那么让我们返回它,因为它已经存在。如果我们不这样做,一个线程可以获得它的单例并对它做一些事情,而我们只是在它的变化和效果上压路机。
如果没有,让我们锁定它并返回一个新的。通过持有锁,我们现在可以从另一端保护单例。另一个线程等待锁,并注意到它已经被创建(根据内部null比较)返回现有的锁。如果我们没有获得锁,线程都会在更改上进行压路机操作,并且发现它们的更改也被销毁了。请注意,您帖子中的代码块是不完整的。如果任何null检查使用else块返回false,则需要返回_instance。
现在,如果我们在单线程环境中,这就不重要了。我们可以只使用:
public static MySingleton getInstance() {
if (_instance==null) {
_instance = new MySingleton();
}
else return _instance;
}在较新的版本中,java在许多情况下使用此行为,作为其库的一部分,在花费时间获取锁之前检查是否需要锁。以前,它要么无法获得锁(坏的,数据丢失),要么立即获得锁(坏的,更有可能减速和死锁)。
为了线程安全,您仍然应该在自己的类中实现它。
发布于 2013-06-30 09:28:23
他没有解释为什么它会在这句话中失败。他只是在解释双重检查锁定。他可能在其他地方提到了双重检查锁定本身在Java1.5之前不起作用的事实。但那是很久以前的事了。
发布于 2013-06-30 09:28:33
我在维基百科上找到了对不同的Singleton实现的最好的解释,它们的缺陷以及什么是最好的。请访问以下链接:
http://en.wikipedia.org/wiki/Singleton_pattern
希望它能帮上忙!
https://stackoverflow.com/questions/17386227
复制相似问题