欢迎您光临本小站。希望您在这里可以找到自己想要的信息。。。

java 单例模式中双重检查锁定 volatile 的作用?

java water 2261℃ 0评论

image.png

volatile 是保证了可见性还是有序性?

有序性:是因为 instance = new Singleton(); 不是原子操作。编译器存在指令重排,从而存在线程1 创建实例后(初始化未完成),线程2 判断对象不为空,但实际对象扔为空,造成错误。

可见性:是因为线程1 创建实例后还只存在自己线程的工作内存,未更新到主存。线程 2 判断对象为空,创建实例,从而存在多实例错误。

看题目描述,其实题主已经清楚了volatile的禁止指令重排序、保证内存可见性的作用。只是想知道在单例模式的双重检查锁定中volatile的作用而已。

个人观点是,两种作用都有:

volatile对singleton的创建过程的重要性:

  • 禁止指令重排序(有序性)

实例化一个对象其实可以分为三个步骤:

  (1)分配内存空间。

  (2)初始化对象。

  (3)将内存空间的地址赋值给对应的引用。

但是由于操作系统可以对指令进行重排序,所以上面的过程也可能会变成如下过程:

  (1)分配内存空间。

  (2)将内存空间的地址赋值给对应的引用。

  (3)初始化对象

如果是这个流程,多线程环境下就可能将一个未初始化的对象引用暴露出来,从而导致不可预料的结果(如题目的描述,这里就是因为 instance = new Singleton(); 不是原子操作,编译器存在指令重排,从而存在线程1 创建实例后(初始化未完成),线程2 判断对象不为空后对其操作,但实际对象仍为空,造成错误)。因此,为了防止这个过程的重排序,我们需要将变量设置为volatile类型的变量,volatile的禁止重排序保证了操作的有序性。

  • Singleton对象的内存可见性

这里由于synchronized锁的是Singleton.class对象,而不是Singleton对象,所以synchronized只能保证Singleton.class对象的内存可见性,但并不能保证Singleton对象的内存可见性;这里用volatile声明Singleton,可以保证Singleton对象的内存可见性。这一点作用也是非常重要的(如题目的描述,避免因为线程1 创建实例后还只存在自己线程的工作内存,未更新到主存。线程 2 判断对象为空,创建实例,从而存在多实例错误)。

转载请注明:学时网 » java 单例模式中双重检查锁定 volatile 的作用?

喜欢 (0)or分享 (0)

您必须 登录 才能发表评论!