深入理解Java内存模型JMM与volatile关键字
深入理解Java内存模型JMM与volatile关键字
多核并发缓存架构

Java内存模型
Java线程内存模型跟CPU缓存模型类似,是基于CPU缓存模型来建立的,Java线程内存模型是标准化的,屏蔽掉了底层不同计算机的区别。

例子
编写代码来分析
public class VolatileVisibilityTest {
private static boolean initFlag = false;
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("等待数据准备..");
while (!initFlag){
}
System.out.println("============数据准备完毕,执行程序逻辑");
}
}).start();
Thread.sleep(2000);
new Thread(new Runnable() {
@Override
public void run() {
prepareData();
}
}).start();
}
public static void prepareData(){

System.out.println("数据准备中..");
initFlag = true;
System.out.println("数据准备完毕!");
}
}
执行程序,打印结果
并未出现
============数据准备完毕,执行程序逻辑
这段结果
分析
第一个线程给了initFlag为false,第二个执行了prepareData()所以initFlag为true,但是第一个线程中的flag还是为false。
如果给initFlag加个volatile关键字:
public class VolatileVisibilityTest {
private static volatile boolean initFlag = false;
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("等待数据准备..");
while (!initFlag){
}
System.out.println("============数据准备完毕,执行程序逻辑");
}
}).start();
Thread.sleep(2000);
new Thread(new Runnable() {
@Override
public void run() {
prepareData();
}
}).start();
}
public static void prepareData(){
System.out.println("数据准备中..");
initFlag = true;
System.out.println("数据准备完毕!");
}
}
执行程序,返回结果

JMM数据原子操作
- read(读取):从主内存读取数据
- load(载入):将主内存读取到的数据写入工作内存
- use(使用):从工作内存读取数据来计算
- assign(赋值):将计算好的值重新赋值到工作内存中
- strore(存储):将工作内存数据写入主内存
- write(写入):将store过去的变量值赋值给主内存中的变量
- lock(锁定):将主内存变量枷锁,表示为线程独占状态
- unlock(解锁):将主内存变量解锁,解锁后其他线程可以锁定该变量
整个过程如下

JMM缓存不一致问题
总线枷锁(性能太低)
- CPU从主内存读取数据到高速缓存,会在总线对这个数据加锁,这样其他CPU没法去读或写这个数据,直到这个CPU使用完整数据释放锁之后其他CPU才能读取该数据。

MESI缓存一致性协议
- 多个CPU从主内存读取同一个数据到各自的高速缓存,当其中某个CPU修改了缓存里的数据,该数据会马上同步回主内存,其他CPU通过
总线嗅探机制可以感知到数据的变化从而将自己缓存里的数据失效。
- 多个CPU从主内存读取同一个数据到各自的高速缓存,当其中某个CPU修改了缓存里的数据,该数据会马上同步回主内存,其他CPU通过

Volatile可见性底层实现原理
Volatile缓存可见性实现原理
- 底层实现主要是通过汇编lock前缀指令,它会锁定这块内存区域的缓存并回写到主内存,此操作被称为“缓存锁定”,MESI缓存一致性协议机制会阻止同时修改被两个以上处理器缓存的内存区域数据。一个处理器的缓存值通过总线回写到内存会导致其他处理器响应的缓存失效。
Java程序汇编代码查看
- -server -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:CompileCommand=compileonly,*VolatileVisibilityTest.prepareData
- 需要先下载hsdis-amd64

IDEA这样设置
显式出的结果,其中volatile修饰的汇编代码如下:
0x000000000349eaff:
lockadd dword ptr [rsp],0h ;*putstatic initFlag
; - com.tugohost.concurrent.VolatileVisibilityTest::prepareData@9 (line 31)
可见性、原子性与有序性
- 并发编程三大特性:可见性,原子性,有序性
- Volatile保证可见性与有序性,但是不保证原子性,保证原子性需要借助synchronized这样的锁机制。
深入理解Java内存模型JMM与volatile关键字的更多相关文章
- 全面理解Java内存模型(JMM)及volatile关键字(转载)
关联文章: 深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) 深入理解Java注解类型(@Annotation) 深入理解Java类加载器(ClassLoad ...
- 全面理解Java内存模型(JMM)及volatile关键字(转)
原文地址:全面理解Java内存模型(JMM)及volatile关键字 关联文章: 深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) 深入理解Java注解类型( ...
- 全面理解Java内存模型(JMM)及volatile关键字
[版权申明]未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) http://blog.csdn.net/javazejian/article/details/72772461 出自[zejian ...
- 深入理解 Java 内存模型 JMM 与 volatile
Java 内存模型(Java Memory Model,简称 JMM)是一种抽象的概念,并不真实存在,它描述的是一组规范或者规则,通过这种规范定义了程序中各个变量(包括实例字段.静态字段和构成数组对象 ...
- 深入理解Java内存模型JMM
本文转载自深入理解Java内存模型JMM JMM基础与happens-before 并发编程模型的分类 在并发编程中,我们需要处理两个关键问题:线程之间如何通信及线程之间如何同步(这里的线程是指并发执 ...
- Java并发编程:JMM (Java内存模型) 以及与volatile关键字详解
目录 计算机系统的一致性 Java内存模型 内存模型的3个重要特征 原子性 可见性 有序性 指令重排序 volatile关键字 保证可见性和防止指令重排 不能保证原子性 计算机系统的一致性 在现代计算 ...
- 全面理解Java内存模型(JMM)
理解Java内存区域与Java内存模型Java内存区域 Java虚拟机在运行程序时会把其自动管理的内存划分为以上几个区域,每个区域都有的用途以及创建销毁的时机,其中蓝色部分代表的是所有线程共享的数据区 ...
- Java并发指南2:深入理解Java内存模型JMM
本文转载自互联网,侵删 一:JMM基础与happens-before 并发编程模型的分类 在并发编程中,我们需要处理两个关键问题:线程之间如何通信及线程之间如何同步(这里的线程是指并发执行的活动实 ...
- BAT经典面试题,深入理解Java内存模型JMM
Java 内存模型 Java 内存模型(JMM)是一种抽象的概念,并不真实存在,它描述了一组规则或规范,通过这组规范定义了程序中各个变量(包括实例字段.静态字段和构成数组对象的元素)的访问方式.试图屏 ...
随机推荐
- OpenWrt 主的发展版本号trunk MT7620N 无线驱动程序bug
周边环境: OpenWrt Development Trunk: svn co svn://svn.openwrt.org/openwrt/trunk/ BUG: 1. 无线无法建立连接. 2. 无线 ...
- spring boot 配置swagger UI
springboot集成swaggerUI 有这样的需求 1.在每个接口上都增加一个字段: 2.接口文档只展示满足一定条件URL的接口 配置文件 详细看代码 import org.springfram ...
- siliverlight某些事件无法响应
对一些无法响应的时间,需要注册 控件名:XZWT_TreeViewItem 事件:this.XZWT_TreeViewItem_MouseLeftButtonDown 具体注册方法: XZWT_Tre ...
- 程序定义了多个入口点。使用 /main (指定包含入口点的类型)进行编译
原文:请使用/main进行编译,以指定包含入口点类型 在使用VS工具初学C#的时候需要不停的写小程序,觉得每次都新建项目太过麻烦,所以试着把程序写在一个项目下面,结果编译的时候出错了,因为我每个小程序 ...
- .NET环境下有关打印页面设置、打印机设置、打印预览对话框的实现
原文:.NET环境下有关打印页面设置.打印机设置.打印预览对话框的实现 我个人认为,开发MIS,首先就得解决网格的问题,而开发工具为我们提供了如DataGrid.MSHFlexGrid的控件.其次,是 ...
- 基于事件驱动的DDD领域驱动设计框架分享(附源代码)
原文:基于事件驱动的DDD领域驱动设计框架分享(附源代码) 补充:现在再回过头来看这篇文章,感觉当初自己偏激了,呵呵.不过没有以前的我,怎么会有现在的我和现在的enode框架呢?发现自己进步了真好! ...
- ML:吴恩达 机器学习 课程笔记(Week5~6)
Neural Networks: Learning Advice for Applying Machine Learning Machine Learning System Design
- 自己动手写jQuery插件---Tip(提示框)
对jQuery相信很多同学和我一样平时都是拿来主义,没办法,要怪只能怪jQuery太火了,各种插件基本能满足平时的要求.但是这毕竟不是长久之道,古人云:“授之以鱼,不如授之以渔”. 为了方便之前没有接 ...
- 二、OpenSceneGraph3.4第一个示例
1.在VS2015中创建一个OSG的空解决方案,并新建一个控制台工程,取名为Example 工程结构如下图所示: 2.工程设置 "Example"->属性,打开属性选项卡,需 ...
- spring常见十大异常
一.找不到配置文件的异常 [plain] view plaincopy org.springframework.beans.factory.BeanDefinitionStoreException: ...