1、认识volatile

volatile是用来修饰变量的。与synchronized不同,synchronized是用来修饰方法和代码块。volatile称之为轻量级锁,被volatile修改的变量在各个线程之间是可见的,保持线程之间的可见性,可见性是指多个线程共享同一个变量,当一个线程修改了这个变量,另外的线程能感知到这个变量的变化并进行读取。

 

2、volatile实现原理

 


java 多线程 countdownlatch用法 java多线程volatile_高速缓存

计算机内存与cpu结构

在计算机系统中,CPU高速缓存(CPU Cache)是用于减少处理器访问内存所需平均时间的部件。在金字塔式存储体系中它位于自顶向下的第二层,仅次于CPU寄存器。其容量远小于内存,但速度却可以接近处理器的频率。cpu每个核心都有对应的高速缓存,而且是相对隔离的。线程都是运行在cpu核上,所以每个线程运行也是完全隔离开来的,线程只与cpu缓存、内存关联,从中拿取运行所需数据。

运行java程序时,代码存放于硬盘上,经过编译,成为class字节码文件,再把字节码文件加载到内存当中,计算机cpu处理器运行时从内存加载运行数据,如需缓存,则缓存至cpu高速缓存中。

当系统运行时,CPU执行计算的过程如下:

  1. 程序以及数据被加载到主内存
  2. 指令和数据被加载到CPU缓存
  3. CPU执行指令,把结果写到cpu高速缓存
  4. cpu高速缓存中的数据写回主内存

那么,上述就会出现个缓存一致性的问题:


java 多线程 countdownlatch用法 java多线程volatile_volatile_02

多线程与多核cpu模拟图

如上图,两个线程t1和t2同时并发运行在不同核心上,开始都读取到a的值为3,此时在线程t2中修改了a的值为5,而在不同核心的线程t1缓存中a的值还是为3,就出现了缓存不一致的问题。

使用volatile修饰变量,就可以解决上述缓存不一致问题,使用volatile修饰后,会发生lock指令(汇编语言),进行资源锁定和更新操作。

当两条线程t1与t2同时操作内存中的一个volatile变量a时:

  1. 线程t2修改变量a的值后,t2会发出一条lock指令,这条lock指令至关重要;
  2. 发出的lock指令会将当前处理器缓存行的最新数据a的值写回到内存当中,同时让其他处理器缓存中对应变量a的缓存行内容失效;
  3. 线程t1在使用自己缓存中的变量a时,发现a已失效,重新从内存中读取a的值,此时读取到的为最新的值;