[英]Singleton Design Pattern Double Checked Locking
if (searchBox == null) { //1
synchronized (SearchBox.class) {
if (searchBox == null) { //2
searchBox = new SearchBox();
}
}
}
这是我为 singleton 模式定制的 class。 在这段代码中,我使用上面的双重检查锁定。 当我在某些来源上阅读了许多帖子时,他们说双重检查很有用,因为它可以防止同时运行的两个并发线程生成两个不同的对象。 根据线程概念,线程调度程序一次只执行一个线程。 那么 2 个线程将如何尝试执行上述代码。
请给我解释一下。 我理解错了什么?
谢谢:)
您不希望 2 个线程同时执行代码。 这是singleton 。 单吨。 在任何给定时间,都应该只有一个 object 实例。 如果两个线程同时运行相同的代码,他们可能会不小心创建两个searchBox
,然后就不会是一吨了,不是吗?
那里的synchronized
允许您做的是保证 singleton 的初始化是线程安全的(不是序列化安全的,也不是您使用基于枚举的单例获得的所有其他好处)。 通过线程安全,这意味着您不会让 2 个线程同时运行代码。 他们完全可以一个接一个地运行代码,此时第二个线程将不会重新实例化 singleton,因为它已经被明显地(对第二个线程)初始化。
类加载器将首先加载 static 字段,因此实例将在任何线程调用方法 getInstance() 之前可用,因此对于有效和干净的 Singleton 考虑使用此技术并避免所有昂贵的同步
public class SearchBox{
private static SearchBox instance = new SearchBox();
private SearchBox(){throw new OperationNotAllowedException();}
public static SearchBox getInstance(){
return instance;
}
public SomeReturn instanceMethod(){return ...}
您发布的代码片段是线程安全的。 即使你去掉外部的if
条件,也不会有问题。
if (searchBox == null) { //1
synchronized (SearchBox.class) {
if (searchBox == null) { //2
searchBox = new SearchBox();
}
}
}
那为什么我们需要外部if
条件呢?
为了提高性能。
假设我们没有第一个如果块和searchbox
object 已经创建。 由于同步阻塞,线程将被阻塞。 在这种情况下,外部if
块将阻止线程进入等待阶段。
替代方法,您可以使用 static 内部 class 来实现 Singleton 模式
public class Singleton {
private static class SingletonHolder {
public static final Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
}
上述代码段的来源: 为什么 static 内部 class singleton 线程安全
双重检查锁定存在致命缺陷。 问题是,这个语句几乎可以肯定分配了多个变量:
searchBox = new SearchBox();
除了对searchBox
的赋值之外,还有其他几个赋值来初始化新的SearchBox
实例。
任何其他尝试在没有同步的情况下查看searchBox
的线程都可能会看到这些分配的发生顺序与它们在创建 singleton 的线程中发生的顺序不同。
That means, if thread A creates the singleton, and then thread B comes along and subsequently finds searchBox != null
, then thread B will not enter the synchronized
block, and thread B could see the singleton object in an uninitialized or a partially initialized state .
必须安全发布singleton object。 Andy Turner 对原始问题的评论(见上文)列举了几种不同的方法来做到这一点。
PS:您可以通过将searchBox
变量声明为volatile
来“修复”双重检查锁定,但是访问searchBox
的成本几乎与锁定锁定的成本一样高。 最好只使用上面提到的一种安全发布模式。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.