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

Java 单例设计模式双重检查锁定,java,multithreading,design-patterns,singleton,synchronized,Java,Multithreading,Design Patterns,Singleton,Synchronized,这是我为singleton模式定制的类。在这段代码中,我使用了如上所述的双重检查锁定。当我在一些源代码上读到很多文章时,他们说双重检查很有用,因为它可以防止两个并发线程同时运行,从而生成两个不同的对象。 根据线程概念,线程调度器一次只能执行一个线程。那么2个线程将如何尝试执行上述代码 请给我解释一下。我理解错了什么 谢谢:)您不希望两个线程同时执行代码。是单身汉。辛格尔顿。在任何给定的时间里,只应该有一个对象的实例。如果两个线程同时运行相同的代码,它们可能会意外地创建两个searchBoxes,

这是我为singleton模式定制的类。在这段代码中,我使用了如上所述的双重检查锁定。当我在一些源代码上读到很多文章时,他们说双重检查很有用,因为它可以防止两个并发线程同时运行,从而生成两个不同的对象。 根据线程概念,线程调度器一次只能执行一个线程。那么2个线程将如何尝试执行上述代码

请给我解释一下。我理解错了什么


谢谢:)

您不希望两个线程同时执行代码。是单身汉。辛格尔顿。在任何给定的时间里,只应该有一个对象的实例。如果两个线程同时运行相同的代码,它们可能会意外地创建两个
searchBox
es,那么它就不会是一个单例,不是吗


那里的
synchronized
允许您做的是保证单例的初始化是线程安全的(不是序列化安全的,也不是使用基于枚举的单例可以获得的所有其他好处)。线程安全意味着不会有两个线程同时运行代码。它们完全可以一个接一个地运行代码,此时第二个线程将不会重新实例化singleton,因为它已经(对第二个线程)进行了明显的初始化。

classloader将首先加载静态字段,因此在任何线程调用方法getInstance之前,该实例都是可用的() 因此,对于一个有效和干净的单体考虑使用这种技术,避免所有昂贵的同步

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

您发布的代码段是线程安全的。即使删除外部
if
条件,也不会有问题

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块和
searchbox
对象已经创建。线程将由于同步块而被阻塞。在这种情况下,外部
if
块将停止线程进入等待阶段

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

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

上述代码段的来源:

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

searchBox=newsearchbox();

除了分配给
searchBox
,还将有其他几个分配来初始化新的
searchBox
实例

任何其他试图在不同步的情况下查看
searchBox
的线程,都可能会看到这些赋值的发生顺序与创建单例的线程中发生的顺序不同

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

单例对象必须是。Andy Turner对原始问题的评论(见上文)列举了几种不同的方法



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

有更好的方法来创建单例,例如single元素枚举,或延迟持有者,甚至只是一个急切初始化的静态最终字段。不要使用双重检查锁定。检查这个。已经有人问过了。Re,“他们说双重检查…阻止两个并发线程…生成两个不同的对象。”正是锁定阻止线程创建多个实例。双重检查部分应该是一种优化。它曾在任何只有一个CPU的计算机上工作,但如果您试图在多处理器机器上使用它(即,在大多数现代工作站、服务器和移动电话上),它就有一个致命的缺陷我也在考虑同样的问题。但是它会为不同的进程创建不同的实例。单例模式没有很好的理由,更不用说双重检查锁定了。我同意你的观点。但是根据线程概念,线程调度程序一次只执行一个线程。那么两个线程将如何尝试执行上面的code.@saurabhlandge好吧,这就是你把事情搞混的地方。2个线程可以、将要和确实同时运行。否则,你根本就不需要
synchronized
关键字。正确。但是内部if条件有什么用?当我们检查实例是否为null时。在外部循环中,我们检查实例是否为null。如果为null,则线程将获取类上的锁并创建实例。根据线程调度程序,一次只执行一个线程。@saurabhlandge如果两个线程同时进入该方法并同时检查外部If条件会怎么样?在这种情况下,内部If条件作为安全点。
public class Singleton  {    
    private static class SingletonHolder {    
        public static final Singleton instance = new Singleton();
    }    

    public static Singleton getInstance() {    
        return SingletonHolder.instance;    
    }    
}