懒汉式模式下指令重排序问题的分析与解决

在执行程序时,为了提高性能,编译器和处理器常常会对指令做重排序。重排序分3种类型:

1.编译器优化的重排序。编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。
2、指令级并行的重排序。现代处理器采用了指令级并行技术(Instruction-Level Parallelism,ILP)来将多条指令重叠执行。如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序。
3.内存系统的重排序。由于处理器使用缓存和读/写缓冲区,这使得加载和存储操作看上去可能是在乱序执行。

我们发现当线程1到达指定的代码块后,如果此时指令重排序,就会使我们的线程2 判断instance是不为null的  他会直接return instance 但是此时线程1的instance 并没有进行初始化,只是赋值了。所以就会导致线程2的instance不可用。

解决的方法:

加上volatile关键字

volatile的作用

  • 保证变量的可见性
    volatile关键字的作用就是保证共享变量的可见性。什么是可见性呢,就是一个线程读变量,总是能读到它在内存中的最新的值,也就是说不同的线程看到的一个变量的值是相同的。CPU都是有行缓存的,volatile能让行缓存无效,因此能读到内存中最新的值。
  • 保证赋值操作的原子性
    原子性就是不能被线程调度打断的操作,是线程安全的操作,对于原子性操作,即使在多线程环境下,也不用担心线程安全问题或者数据不一致的问题。有些变量的赋值本身就是原子性的,比如对boolean,对int的赋值,但是像对于long或者double则不一定,如果是32位的处理器,对于64位的变量的操作可能会被分解成为二个步骤:高32位和低32位,由此可能会发生线程切换,从而导致线程不安全。如果变量声明为volatile,那么虚拟机会保证赋值是原子的,是不可被打断的。
  • 禁止指令重排
    正常情况下,虚拟机会对指令进行重排,当然是在不影响程序结果的正确性的前提下。volatile能够在一定程度上禁止虚拟机进行指令重排。还有就是对于volatile变量的写操作,保证是在读操作之前完成,假设线程A来读变量,刚好线程B正在写变量,那么虚拟机会保证写在读之前完成。 

如果还有疑问可以看b站的视频讲解:

02.设计模式之单例模式_哔哩哔哩_bilibili

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值