Java核心复习—— volatile 与可见性
一、介绍
volatile保证共享变量的“可见性”。可见性指的是当一个线程修改变量时,另一个线程能读到这个修改的值。
这里就要提出几个问题。
- 问题1:为什么一个线程修改时,另一个线程可能会“看不见”?
- 问题2:这种可见性是如何实现的?
二、问题1 变量为何“不可见”
回答:是由于缓存导致的可见性问题
2.1 为什么要引入缓存?
是为了解决性能问题。CPU的处理速度远远快于内存的读取速度(CPU与内存之间的瓶颈也叫“冯诺依曼瓶颈”),所以处理器不直接和内存通信,而是设置内部缓存(L1、L2...),内存的数据会读取到内部缓存中,CPU直接从内部缓存中读取数据处理。
2.2 L1、L2、L3有何区别?
L1、L2、L3是CPU三级缓存,CPU缓存的定义为CPU与内存之间的临时数据交换器,它的出现是为了解决CPU运行处理速度与内存读写速度不匹配的矛盾。
读取速度 L1 > L2 > L3
容量大小 L1 < L2 < L3
L1又分为一级数据缓存、一级指令缓存,分别用于存放数据、执行数据的指令解码。

2.3 只管高速缓存中的变量,不管内存中的变量行不行?
多个处理器修改变量写到高速缓存,高速缓存中存储的变量值是最新,下次不管内存中的变量值,直接从高速缓存中获取不就行了?
回答:当然不行。
为什么?因为每个处理器都有自己的高速缓存,一个变量在A处理器的高速缓存中修改,B处理器可能感知不到。

三、问题2 变量如何变为“可见”
为了保证在多处理器下,缓存一致,就设置一个缓存一致的协议。每个处理器通过嗅探在总线传播的数据来检查自己缓存的值是否是过期的。
当处理器发现自己的缓存行对内的内存地址被修改,就会将当前处理器的缓存行设置成无效状态,当需要对数据进行修改时,重新从内存中读到高速缓存中。
3.1 具体是如何实现?
当变量被volatile修饰,编译成汇编时,会增加一个Lock前缀指令。
Lock前缀指令的作用:
- Lock前缀指令,会让处理器缓存回写到内存
- 一个处理器缓存回写到内存,导致其他处理器的缓存无效
参考文档
[1]: 《Java并发编程的艺术》
[2]: Java并发编程-volatile
[3]: CPU与内存的那些事
[4]: 超能课堂(133):为什么CPU缓存会分为L1、L2、L3?
Java核心复习—— volatile 与可见性的更多相关文章
- Java并发:volatile内存可见性和指令重排
volatile两大作用 1.保证内存可见性 2.防止指令重排 此外需注意volatile并不保证操作的原子性. (一)内存可见性 1 概念 JVM内存模型:主内存和线程独立的工作内存 Java内存模 ...
- Java核心复习—— 原子性、有序性与Happens-Before
一. 产生并发Bug的源头 可见性 缓存导致的可见性问题 原子性 线程切换带来的原子性问题 有序性 编译优化带来的有序性问题 上面讲到了 volatile 与可见性,本章再主要讲下原子性.有序性与Ha ...
- Java核心复习——J.U.C AbstractQueuedSynchronizer
第一眼看到AbstractQueuedSynchronizer,通常都会有这几个问题. AbstractQueuedSynchronizer为什么要搞这么一个类? 这个类是干什么的.有什么用? 这个类 ...
- Java核心复习——线程池ThreadPoolExecutor源码分析
一.线程池的介绍 线程池一种性能优化的重要手段.优化点在于创建线程和销毁线程会带来资源和时间上的消耗,而且线程池可以对线程进行管理,则可以减少这种损耗. 使用线程池的好处如下: 降低资源的消耗 提高响 ...
- Java核心复习 —— J.U.C 并发工具类
一.CountDownLatch 文档描述 A synchronization aid that allows one or more threads to wait until* a set of ...
- Java核心复习——synchronized
一.概念 利用锁机制实现线程同步,synchronized关键字的底层交由了JVM通过C++来实现 Java中的锁有两大特性: 互斥性 同一时间,只允许一个线程持有某个对象锁. 可见性 锁释放前,线程 ...
- Java核心复习——CompletableFuture
介绍 JDK1.8引入CompletableFuture类. 使用方法 public class CompletableFutureTest { private static ExecutorServ ...
- Java核心复习—— ThreadLocal源码分析
ThreadLocal,叫做线程本地存储,也可以叫做线程本地变量.ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量. 一.如何使用 class Acce ...
- Java核心复习——J.U.C LinkedBlockingQueue源码分析
参考文档 LinkedBlockingQueue和ArrayBlockingQueue的异同
随机推荐
- vue的事件对象
事件对象: v-on:click/mouseover 简写: @click="" @click="show($event)" <input t ...
- c#的异步处理思路和vue前端中异步处理思路比较
前语:目前工作在做的项目是前端基于vue的组件式开发,通过api接口调用,后端数据逻辑是一个c#实现的WCF服务 1.总结自己在c# .NET 4.5后的新异步方式 async搭配await来实现 ...
- 关于Vue-elementUI中,给input手动赋值之后无法修改的问题解决
方案一:在data中给input的值赋一个初始值 方案二:在给input赋值时,使用this.$set
- JS做动态表格
在后台将数据发送过来后,你需要将这些数据做成表格,实现一般表格管理功能 例如这种数据格式, 首先要创建table 在table中添加thead 在thead中添加tr 循环数组,且创建开头的inpu ...
- Python-pptx库的运用
Win32com该库需要调用Microsoft PowerPoint,我将重新安装计算机Win 10,简单安装了pycharm的最新版本,然后发现创建的项目与之前的创建的项目结构不同.还有更多这样的事 ...
- VIO的一些随笔
大公司跑在手机的似乎都是滤波MSCKF那种,有优化的但似乎功耗不行.还有就是杂交的前端滤波后面在挂地图,反正国内的似乎就是SVO, VINS, ORBSLAM,MSCKF组合起来. 缺啥补啥,那个太烂 ...
- ORA-00001:unique constraint violated解决
转自:https://www.2cto.com/database/201211/172340.html ORA-00001:unique constraint violated解决 今天往数据库中插入 ...
- 【数字图像处理】gamma变换
论文:gamma校正的快速算法及其c语言实现 gamma变换实现过程 假设图像中有一个像素,值是 200 ,那么对这个像素进行校正必须执行如下步骤: 1. 归一化 :将像素值转换为 0 - 1 之 ...
- STM8 定时器
中断映射表 对应stm8_interrupt.c #pragma vector=1 __interrupt void TRAP_IRQHandler(void) { } #pragma vector= ...
- sql server统计总成绩和排名
这里的图片可以拖拽到一个新页面查看原图!!!! 这里有两个表,需要查询总成绩和排名 Sql语句: select ST.name,SE.Chinese,SE.Math,SE.English, ( SE. ...