单例设计模式双重检查锁定

时间:2019-09-30 14:51:36

标签: java multithreading design-patterns singleton synchronized

if (searchBox == null) { //1
    synchronized (SearchBox.class) {
        if (searchBox == null) {  //2
            searchBox = new SearchBox();
        }
    }
}

这是我的单例模式自定义类。在此代码中,我如上所述使用了双重检查锁定。当我在某些来源上读到许多帖子时,他们说,双重检查很有用,因为它可以防止两个同时运行的并发线程同时产生两个不同的对象。 根据线程概念,线程调度程序一次只执行一个线程。然后2个线程将如何尝试执行以上代码。

请向我解释。我了解错了什么?

谢谢:)

4 个答案:

答案 0 :(得分:0)

不想让2个线程同时执行代码 。这是一个单子吨。在任何给定时间都应该只存在该对象的一个​​实例。如果两个线程一次运行相同的代码,则它们可能会意外地创建两个searchBox,然后不是 single ton,不是吗?

那里的synchronized允许您做的是确保单例的初始化是线程安全的(不是序列化安全或基于枚举的单例获得的所有其他好处)。通过线程安全,这意味着您将不会有2个线程同时运行代码 。完全可以让他们一个接一个地运行代码,这时第二个线程将不会重新实例化单例,因为它已经(在第二个线程中)已经被初始化。

答案 1 :(得分:0)

类加载器将首先加载静态字段,因此该实例将在任何线程调用方法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 ...} 

答案 2 :(得分:0)

您发布的代码段是线程安全的。即使您删除了外部struct LastFour { private var closeEvents: [String] func close(at index: Int) -> String { } } 条件,也不会有问题。

if

那为什么我们需要外部if (searchBox == null) { //1 synchronized (SearchBox.class) { if (searchBox == null) { //2 searchBox = new SearchBox(); } } } 条件?
为了提高性能。

假设没有第一个if块和if对象已经创建。线程将由于同步阻塞而被阻塞。在这种情况下,外部searchbox块将阻止线程进入等待阶段。

另一种方法,您可以使用静态内部类来实现Singleton模式

if

上述摘要的来源:why is static inner class singleton thread safe

答案 3 :(得分:0)

双重检查锁定存在致命缺陷。问题是,该语句几乎可以肯定会分配多个变量:

searchBox = new SearchBox();

除了对searchBox的赋值之外,还将有其他几种赋值来初始化新的SearchBox实例。

任何其他尝试查看searchBox 而没有同步的线程都可能会看到这些分配以与它们在分配中的发生方式不同的顺序发生在。创建单例的线程。

这意味着,如果线程A创建单例,然后线程B出现并随后找到searchBox != null,则线程B将进入synchronized块,并且线程B 可以看到处于未初始化或部分初始化状态的单例对象。

单例对象必须为 safely published 。安迪·特纳(Andy Turner)对原始问题的评论(见上文)列举了几种不同的方法来实现这一目标。


PS:您可以通过声明searchBox变量为volatile来“修复”双重检查锁定,但是访问searchBox的成本几乎与锁定锁。最好只使用上述一种安全的发布模式。

相关问题