volatile关键字

129 阅读2分钟

「这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战

java虚拟机提供的最轻量级的同步锁机制,具有内存可见性以及禁止指令重排序两大特性。 但是 volatile 不能保证原子性,例如:i++这种操作,volatile是不能保证其原子性操作的。

内存可见性

保证了不同线程对在这个变量进行操作时的可见性,即一个线程修改了某个变量的值,这新值对其他线程来说是立即可见的

重排序

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

java源码到编译执行会经过以下重排序

1.png

原理

volatile 变量进行写操作时,JMM 会向处理器发送一条 Lock 前缀的指令,将该线程对应的本地内存中的共享变量值刷新到主内存中。 Lock 前缀指令实际上相当于一个内存屏障(也成内存栅栏),它确保指令重排序时不会把其后面的指令排到内存屏障之前的位置,也不会把前面的指令排到内存屏障的后面;即在执行到内存屏障这句指令时,在它前面的操作已经全部完成。

使用原则

  • 使用volatile修饰的变量会对多个线程可见,也就是说任何线程都可以看到被volatile修饰的变量的最终值。
  • volatile并不能替代synchronized,因为volatile只提供了可见性,并没有提供互斥性;在多线程并发修改某个变量值时,依然会出现并发问题。 所以最适合用的场景是一个线程修改被volatile修饰的变量,其他多个线程获取这个变量的值。 当多个线程并发修改某个变量值时,必须使用synchronized来进行互斥同步。