• a=a+1背后的内存模型和CPU高速缓存


      学过JAVA的人都知道,程序运行过程中的临时数据,都是从外部存储设备调入内存(物理内存)中,再进行读写操作的。而计算机在执行程序时,对程序的每条指令都是在CPU中执行的,而指令的执行,势必涉及到对数据的读写操作。

      于是就产生了这样一个问题,CPU指令的执行速度是很快的,但是从内存中读取和写入数据的速度却是比较慢的。如果对数据的任何操作,都需要CPU和内存打交道,而由于内存的读取速度远远慢于CPU的执行速度,这样就大大降低了CPU执行的效率,于是就有了CPU高速缓存的概念。

      CPU,CPU高速缓存,内存协同工作过程

      1、程序运行过程,会将所需要操作的业务数据加载到内存中,并复制一份到CPU的高速缓存中。

      2、CPU指令执行时,直接从CPU高速缓存中读取和写入数据,提高工作效率。

      3、CPU运算结束后,将结果写入CPU高速缓存,此时再同步至内存中。

      

      多线程场景下a = a + 1的难题

      程序执行该代码时,JVM进程中首先开启一个线程,从外部存储设备中加载class文件至内存中并赋予了a初始值,并将a值复制一份存储至CPU高速缓存中。运算时,CPU指令首先从高速缓存中读取a值,进行+1操作后将结果写入高速缓存中,再由高速缓存同步至内存中,于是一个加法运算的全过程就顺利完成了。

      这个代码在单线程的场景中,是没有任何问题的。但如果是运行在多核CPU的多线程场景下就会出问题了。

      在多核CPU下,每个线程都可能拥有自己独立的CPU,每个线程运行时都有自己的CPU高速缓存,这样就容易造成计算结果的脏数据。

      假设a在JVM加载初始化过程被赋值为0,线程A和B同时执行a = a + 1的操作,此时我们预期的结果可能都是a最终的结果为2。

      但是,如果线程A,B同时从内存中复制了a值至各自的CPU高速缓存中,A执行完了a = 1写入自己线程的缓存,再同步回内存,B也如此。这样一来,最终a的值就定格在了1,这是和预期结果所相悖的。也就是说,在多CPU,多线程编程的场景下,很有可能存在计算结果为脏数据的现象。

      为解决该难题,就需要使用volatile关键字对变量进行修饰了,至于volatile关键字为啥有此神奇功效,请看本博客的《深入剖析volatile关键字》。

      

  • 相关阅读:
    函数集
    2019.1.7
    第九次团队作业-测试报告与用户使用手册
    α版本升升备忘录下载链接
    系统设计和任务分配(个人)
    团队作业说明
    备忘录-团队选题报告
    需求分析与原型设计---升升备忘录
    项目——四则运算器
    Hello Django
  • 原文地址:https://www.cnblogs.com/jiyukai/p/6937198.html
Copyright © 2020-2023  润新知