先贴一下 volatile 的作用定义

如果一个字段被声明成volatile,Java线程内存模型确保所有线程看到这个变量的值是一致的

首先问题就来了,一个共享变量再被volatile修饰过后,怎么被确保所有线程看到的这个变量的值是一致的的呢,也就是说volatile是如何来保证可见性的呢?

在X86处理器下通过工具获取JIT编译器生成的汇编指令来查看对volatile进行写操作时,CPU会做什么事情。

private volatile instance = new Singleton(); 

转变成汇编代码,如下。

0x01a3de1d: movb $0×0,0×1104800(%esi);

0x01a3de24: lock addl $0×0,(%esp);

有 volatile 变量修饰的共享变量进行写操作的时候会多出第二行汇编代码,通过查IA-32架构软件开发者手册可知,Lock前缀的指令在多核处理器下会引发了两件事情。

1)将当前处理器缓存行的数据写回到系统内存。
2)这个写回内存的操作会使在其他CPU里缓存了该内存地址的数据无效。

第一件事很容易理解,处理器在修改数据后通常都是先写入到缓存中,但是并不会第一时间写回到主内存中。

被 volatile 修饰后,这个变量被操作后会立即被写回到主内存中。(当然整个过程会比较复杂,但是我们只需要从结果上来看和简化理解就OK了。)

那第二件事中这个写回内存的操作是如何使其他CPU里缓存了该内存地址的数据无效的呢?

为了提高处理速度,处理器不直接和内存进行通信,而是先将系统内存的数据读到内部缓存(L1,L2或其他)后再进行操作,但操作完不知道何时会写到内存。
如果对声明了volatile的变量进行写操作,JVM就会向处理器发送一条Lock前缀的指令,将这个变量所在缓存行的数据写回到系统内存。
但是,就算写回到内存,如果其他处理器缓存的值还是旧的,再执行计算操作就会有问题。
所以,在多处理器下,为了保证各个处理器的缓存是一致的,就会实现缓存一致性协议,每个处理器通过嗅探在总线上传播的数据来检查自己缓存的值是不是过期了,
当处理器发现自己缓存行对应的内存地址被修改,就会将当前处理器的缓存行设置成无效状态,当处理器对这个数据进行修改操作的时候,会重新从系统内存中把数据读到处理器缓存里。

这么看来的话,各处理器之间是通过实现缓存一致性协议来完成第二件事的。

那么“每个处理器通过嗅探在总线上传播的数据来检查自己缓存的值是不是过期了”,这里的处理器是如何嗅探的呢?

我百度了半天也没有单独将如何嗅探的,但是看了一遍博文后(并发研究之CPU缓存一致性协议(MESI)) ,我有了一些自己的理解,当然也只是为了简化复杂流程的简化理解。

以上是目前流行的多级缓存结构简化图,

处理器无论是想要加载数据或者写回数据,都需要通过总线(图中的②bus)来传播,

那么我们也就可以将 “处理器通过嗅探在总线上传播的数据” 这样的操作形象的理解为处理器监听 总线 上的所有修改操作,

当处理器发现自己的缓存中的某个数据在总线上被其他的处理器修改了,那么就将自己缓存中的这个数据的状态变成无效状态,

然后当处理器在处理这个无效状态的数据时,会重新去主内存中加载这个数据,然后在进行相应的操作。

比如:CPU A的cache a 已经缓存了 x,然后 CPU B的cache b 也已经缓存了 x,这时 CPU A要修改 x 的值,

然后先将修改后的数据写回到主内存中,在写回到主内存的同时被CPU B嗅探到了,并且发现这个数据在自己的cache b中也存在,然后CPU B就先将自己cache b中的 x 的状态设置成无效,

当CPU B处理到 x 时,发现 x 的状态是无效的,就只能先去主内存中重新加载 x 的值后再操作。

以上便是个人对于处理器嗅探操作的简化理解,虽然简化理解后的流程顺序和原本的流程顺序有所出入,但是这样简化理解只是为了方便自己理解和记忆。

需要了解具体的整体操作流程的话,可以去看上面提到的那边博文。

volatile作用与处理器嗅探的简解的更多相关文章

  1. python ConfigParser、shutil、subprocess、ElementTree模块简解

    ConfigParser 模块 一.ConfigParser简介ConfigParser 是用来读取配置文件的包.配置文件的格式如下:中括号“[ ]”内包含的为section.section 下面为类 ...

  2. Jmeter(十八) - 从入门到精通 - JMeter后置处理器 -下篇(详解教程)

    1.简介 后置处理器是在发出“取样器请求”之后执行一些操作.取样器用来模拟用户请求,有时候服务器的响应数据在后续请求中需要用到,我们的势必要对这些响应数据进行处理,后置处理器就是来完成这项工作的.例如 ...

  3. UE4 RHI与Render模块简解

    UE4中的RHI指的是Render hardware interface,作用像Ogre里的RenderSystem,针对Dx11,Dx12,Opengl等等平台抽象出相同的接口,我们能方便能使用相同 ...

  4. zabbix基本监控各指标简解

    监控项目及使用模板 监控http和https: Template App HTTP Service     Template App HTTPS Service 监控cpu,内存,网络等: Templ ...

  5. Jmeter(十七) - 从入门到精通 - JMeter后置处理器 -上篇(详解教程)

    1.简介 后置处理器是在发出“取样器请求”之后执行一些操作.取样器用来模拟用户请求,有时候服务器的响应数据在后续请求中需要用到,我们的势必要对这些响应数据进行处理,后置处理器就是来完成这项工作的.例如 ...

  6. Spring ApplicationContext 简解

    ApplicationContext是对BeanFactory的扩展,实现BeanFactory的所有功能,并添加了事件传播,国际化,资源文件处理等.   configure locations:(C ...

  7. HTTP协议简解

    1.什么是http协议 http协议: 浏览器客户端 与  服务器端 之间数据传输的规范 2.查看http协议的工具 1)使用火狐的firebug插件(右键->查看元素->网络) 2)使用 ...

  8. python函数基础以及函数参数简解

    python中函数分为函数.内置函数Python所有的内置函数 自定义函数要使用def语句,依次写出函数名.括号.括号中的参数和冒号:,然后,在缩进块中编写函数体,函数的返回值用return语句返回. ...

  9. AC题目简解-数据结构

    A - Japan  POJ 3067 要两条路有交叉,(x1,y1)(x2,y2)那么需要满足:(x1-x2)*(y1-y2)<0判断出这是求逆序的问题 树状数组求逆序,先通过自定义的比较器实 ...

随机推荐

  1. 关于fpga的后仿真重要性

    也许你天天做些fpga,写完代码就直接编译成功,锁定引脚后,马上使用signaltaII软件. 也许你一天,你发现signaltapII看信号的痛苦,一个源代码文件修改一点,要花个20分钟编译一次. ...

  2. 搜索await page.waitForSelector(allResultsSelector);

    /** * Copyright 2017 Google Inc. All rights reserved. * * Licensed under the Apache License, Version ...

  3. SciPy k均值聚类

    章节 SciPy 介绍 SciPy 安装 SciPy 基础功能 SciPy 特殊函数 SciPy k均值聚类 SciPy 常量 SciPy fftpack(傅里叶变换) SciPy 积分 SciPy ...

  4. KAZE特征和各向异性扩散滤波

    kaze feature: http://www.doc88.com/p-6911376909693.html 各向异性扩散滤波  Scale-space and edge detection usi ...

  5. 小程序导航组件navigator活学活用

    小程序开发中必不可少的组件navigator,虽然使用频率非常高,但是却没多少人能灵活运用. 先说navigator组件的用处: 它的主要用处是跳转执行,跳转可分为当前页面内跳转.前往页面外部的跳转. ...

  6. 吴裕雄 Bootstrap 前端框架开发——Bootstrap 字体图标(Glyphicons):glyphicon glyphicon-user

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name ...

  7. Linux: 桥接 NET HOST-only

    桥接 虚拟机会利用真实的网卡和真实计算机之间通信  还能和同一局域网之间的计算机之间通信 缺点:会耗费一个ip地址 NET:虚拟机会通过VMnet8 虚拟的网卡与真实计算机之间通信    如果真实计可 ...

  8. HihoCoder第十周:后序遍历

    也就在大二学数据结构的时候知道了树的前序遍历.后序遍历.中序遍历.之后就忘了,在之后就是大四研究生老师考我,我当时还不知道,真够丢人的.自此之后,知道了如何通过其中两个得到第三个,但是也没有编程实现过 ...

  9. [ cocos2d-JS ] 启动项目

    1, 打开windows命令行 2, cd 到项目的文件夹 3, 执行 cocos run -p web

  10. cf754 754D - Fedor and coupons

    2个多小时,弱智了..(连A都做不对,就不要做D了(迷)) #include<bits/stdc++.h> #define lowbit(x) x&(-x) #define LL ...