繁体   English   中英

Singleton 设计模式双重检查锁定

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM