1、认识volatile
volatile是用来修饰变量的。与synchronized不同,synchronized是用来修饰方法和代码块。volatile称之为轻量级锁,被volatile修改的变量在各个线程之间是可见的,保持线程之间的可见性,可见性是指多个线程共享同一个变量,当一个线程修改了这个变量,另外的线程能感知到这个变量的变化并进行读取。
2、volatile实现原理
计算机内存与cpu结构
在计算机系统中,CPU高速缓存(CPU Cache)是用于减少处理器访问内存所需平均时间的部件。在金字塔式存储体系中它位于自顶向下的第二层,仅次于CPU寄存器。其容量远小于内存,但速度却可以接近处理器的频率。cpu每个核心都有对应的高速缓存,而且是相对隔离的。线程都是运行在cpu核上,所以每个线程运行也是完全隔离开来的,线程只与cpu缓存、内存关联,从中拿取运行所需数据。
运行java程序时,代码存放于硬盘上,经过编译,成为class字节码文件,再把字节码文件加载到内存当中,计算机cpu处理器运行时从内存加载运行数据,如需缓存,则缓存至cpu高速缓存中。
当系统运行时,CPU执行计算的过程如下:
- 程序以及数据被加载到主内存
- 指令和数据被加载到CPU缓存
- CPU执行指令,把结果写到cpu高速缓存
- cpu高速缓存中的数据写回主内存
那么,上述就会出现个缓存一致性的问题:
多线程与多核cpu模拟图
如上图,两个线程t1和t2同时并发运行在不同核心上,开始都读取到a的值为3,此时在线程t2中修改了a的值为5,而在不同核心的线程t1缓存中a的值还是为3,就出现了缓存不一致的问题。
使用volatile修饰变量,就可以解决上述缓存不一致问题,使用volatile修饰后,会发生lock指令(汇编语言),进行资源锁定和更新操作。
当两条线程t1与t2同时操作内存中的一个volatile变量a时:
- 线程t2修改变量a的值后,t2会发出一条lock指令,这条lock指令至关重要;
- 发出的lock指令会将当前处理器缓存行的最新数据a的值写回到内存当中,同时让其他处理器缓存中对应变量a的缓存行内容失效;
- 线程t1在使用自己缓存中的变量a时,发现a已失效,重新从内存中读取a的值,此时读取到的为最新的值;