双检查锁下的单例懒汉模式

发布时间:2026/7/5 9:11:08
双检查锁下的单例懒汉模式 1、什么是单例懒汉模式单例模式保证一个类在JVM中只有一个实例并提供一个全局访问点。懒汉模式在第一次调用获取实例方法时才创建对象而不是类加载时。核心优点是延迟加载节省资源缺点是线程不安全。举个例子publicclassSingleton{privatestaticSingletoninstance1;publicstaticSingletongetInstance1(){if(instance1null){instance1newSingleton();}returninstance1;}对象实例创建流程先分配一片足够放下Singleton对象的空间赋默认值。再执行构造方法初始化对象。建立关联对象引用指向该对象实例。2、单例懒汉模式下的问题问题CPU或者编译器会将第2、3步的指令重排序单线程下不会有问题。多线程下问题有两个T1 如果先执行3还没执行2的时候T2 判断得知对象引用不为空直接返回了未初始化的对象导致错误。会导致重复创建违背单例模式。如果T1在创建对象的过程中另一个线程T2判断得知instance1null那么它会进入对象创建流程从而创建重复对象并替换引用。如何解决错误方案一直接给instance1标记为volatile然后不做任何处理。问题由于它无法确保原子性因此创建过程会受其他线程影响从而导致重复创建。错误方案二双重检查锁问题拿到未初始化对象。具体见下文3、双检查锁失效首先看一下代码publicclassSingleton{privatestaticSingletoninstance2;publicstaticSingletongetInstance2(){if(instance2null){synchronized(Singleton.class){if(instance2null){instance2newSingleton();}}}returninstance2;}}双检查锁对象为空时只让一个线程进去初始化对象。另一个等待线程获取锁后再次判断是否被初始化避免重复创建。为什么能避免重复创建并发调用getInstance2方法的情况下后一个线程判断为空之后还需要等待锁而那个锁被释放之后。锁内部会再次检查该对象是否被创建如果已经被创建则直接跳过对象的创建过程从而避免再次创建。问题只解决了重复创建的问题。还是会出现它被引用但是没有调用构造方法初始化时。另一个线程通过了非空判断直接拿到一个未初始化对象的情况。4、volatile作用volatile 保证变量的可见性和禁止指令重排序但不保证原子性。可见性写 volatile 会立即刷新到主内存读 volatile 从主内存读。重排序修饰的变量前后插入内存屏障防止指令重排。原子性volatile不能保证i这类复合操作的原子性因为读、改、写三步可能被其他线程影响。因此这里直接利用它的禁止指令重排序的作用直接修饰单例对象这样就可以配合synchronized同时保证创建对象过程的原子性、禁止创建过程的指令重排序。volatileprivatestaticSingletoninstance2;