线程中的关键字volatile的介绍

本文详细探讨了缓存一致性问题的根源及解决方法,重点介绍了Java中的volatile关键字如何确保多线程环境下变量的可见性,并对比了其与synchronized的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.首先为什么会有缓存一致性问题,为什么会需要colatile关键字呢?

  • 首先要先了解cpu,在计算机中,cpu和内存的交互最为频繁,相比内存,磁盘读写太慢,但是随着cpu的发展,内存的读写速度也远远赶不上cpu。因此cpu厂商在每颗cpu上加上高速缓存,用于缓解这种情况。
  • cpu上加入了高速缓存这样做解决了处理器和内存的矛盾(一快一慢),但是引来的新的问题 - 缓存一致性
  • 在单核cpu中并在cpu和主内存之间加上高速缓冲内存并没有什么问题,但是在多核cpu中,每个处理器都有各自的高速缓存(L1,L2,L3),而主内存确只有一个 ,而主内存就只有一个,所以问题就产生了
    • 解释:CPU要读取一个数据时,首先从一级缓存中查找,如果没有找到再从二级缓存中查找,如果还是没有就从三级缓存或内存中查找,每个cpu有且只有一套自己的缓存。
    • 为了提高处理速度,处理器不直接和内存进行通信,而是先将系统主内存的数据读到内部缓存(L1,L2或其他)后再进行操作,但操作完不知道何时会写到主内存。
  • 现在的cpu与内存的交互大致如下
  • 正是因为上诉问题,每个线程被不同的cpu执行,然后把改变的值会先写到各自的高速缓存中,然后再由高速缓存把改变后的值刷新到主存中,就是在这期间另一个线程可能读取主存的值并不是最新的

2.下面就介绍一下volatile关键字

  • 我们知道在java中有一大神器就是关键volatile,可以说是和synchronized各领风骚
  • synchronized是阻塞式同步,在线程竞争激烈的情况下会升级为重量级锁
  • 而volatile就可以说是java虚拟机提供的最轻量级的同步机制
  • 各个线程会将共享变量从主内存中拷贝到工作内存(相当于自己的高速缓存区),然后执行引擎会基于工作内存中的数据进行操作处理
  • Java内存模型规定了所有的变量都存储在主内存中。每条线程中还有自己的工作内存,线程的工作内存中保存了被该线程所使用到的变量(这些变量是从主内存中拷贝而来)。线程对变量的所有操作(读取,赋值)都必须在工作内存中进行。不同线程之间也无法直接访问对方工作内存中的变量,线程间变量值的传递均需要通过主内存来完成。

3.volatile到底做了什么?

  • 使用volatile关键字会强制将修改的值立即写入主存;
  • 这个写回内存的操作会使得其他CPU里缓存了该内存地址的数据无效,再其他线程在去自己的缓存中读取数据的时候发现失效了,这时候就会再去主存中读取并且保存在自己的工作去缓存中
  • 正是因为上述两部操作才保证了volatile修饰的变量会立马同步到主存中并且对其他线程可见

4.volatile底层实现原理

  • 如果对声明了volatile的变量进行写操作,JVM就会向处理器发送一条Lock前缀的指令,将这个变量所在缓存行的数据写回到系统内存
  • 但是,就算写回到内存,如果其他处理器缓存的值还是旧的,再执行计算操作还是会有问题
  • 所以我们得出结论:
    • lock前缀的指令会引起处理器缓存写回内存;
    • 一个处理器的缓存回写到内存会导致其他处理器的缓存失效;
    • 当处理器发现本地缓存失效后,就会从内存中重读该变量数据,即可以获取当前最新值
  • 这样针对volatile变量通过这样的机制就使得每个线程都能获得该变量的最新值。

5.下面来讨论一下volatile与Synchronized

  • Synchronized主要针对的是对线程的顺序执行控制
  • volatile主要针对的是对线程的内存可见
  • Synchronized它会阻止其它线程获取当前对象的监控锁,这样就使得当前对象中被synchronized关键字保护的代码块无法被其它线程访问,也就无法并发执行,而且synchronized还会创建一个内存屏障,当一个线程执行完释放锁之后会立即把改变的值刷新到主存中,并把其他线程中的缓存失效掉,这样就可以保证其他先线程会去主存中读取最新的值了。
  • 两者的区别
    • volatile本质是在告诉jvm当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取; synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住。
    • volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的
    • volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性
    • volatile不会造成线程的阻塞(因为是底层对处理器发送了一个lock指令);synchronized可能会造成线程的阻塞。
    • volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化

参考

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值