深入理解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(){
![](https://img2018.cnblogs.com/blog/1330447/201907/1330447-20190710190530342-1378616179.png) 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通过总线嗅探机制可以感知到数据的变化从而将自己缓存里的数据失效。

Volatile可见性底层实现原理

  • Volatile缓存可见性实现原理

    • 底层实现主要是通过汇编lock前缀指令,它会锁定这块内存区域的缓存并回写到主内存,此操作被称为“缓存锁定”,MESI缓存一致性协议机制会阻止同时修改被两个以上处理器缓存的内存区域数据。一个处理器的缓存值通过总线回写到内存会导致其他处理器响应的缓存失效。

    Java程序汇编代码查看

    • -server -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:CompileCommand=compileonly,*VolatileVisibilityTest.prepareData
    • 需要先下载hsdis-amd64

IDEA这样设置

显式出的结果,其中volatile修饰的汇编代码如下:

0x000000000349eaff: lock add dword ptr [rsp],0h ;*putstatic initFlag

; - com.tugohost.concurrent.VolatileVisibilityTest::prepareData@9 (line 31)

可见性、原子性与有序性

  • 并发编程三大特性:可见性,原子性,有序性
  • Volatile保证可见性与有序性,但是不保证原子性,保证原子性需要借助synchronized这样的锁机制。

深入理解Java内存模型JMM与volatile关键字的更多相关文章

  1. 全面理解Java内存模型(JMM)及volatile关键字(转载)

    关联文章: 深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) 深入理解Java注解类型(@Annotation) 深入理解Java类加载器(ClassLoad ...

  2. 全面理解Java内存模型(JMM)及volatile关键字(转)

    原文地址:全面理解Java内存模型(JMM)及volatile关键字 关联文章: 深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) 深入理解Java注解类型( ...

  3. 全面理解Java内存模型(JMM)及volatile关键字

    [版权申明]未经博主同意,谢绝转载!(请尊重原创,博主保留追究权) http://blog.csdn.net/javazejian/article/details/72772461 出自[zejian ...

  4. 深入理解 Java 内存模型 JMM 与 volatile

    Java 内存模型(Java Memory Model,简称 JMM)是一种抽象的概念,并不真实存在,它描述的是一组规范或者规则,通过这种规范定义了程序中各个变量(包括实例字段.静态字段和构成数组对象 ...

  5. 深入理解Java内存模型JMM

    本文转载自深入理解Java内存模型JMM JMM基础与happens-before 并发编程模型的分类 在并发编程中,我们需要处理两个关键问题:线程之间如何通信及线程之间如何同步(这里的线程是指并发执 ...

  6. Java并发编程:JMM (Java内存模型) 以及与volatile关键字详解

    目录 计算机系统的一致性 Java内存模型 内存模型的3个重要特征 原子性 可见性 有序性 指令重排序 volatile关键字 保证可见性和防止指令重排 不能保证原子性 计算机系统的一致性 在现代计算 ...

  7. 全面理解Java内存模型(JMM)

    理解Java内存区域与Java内存模型Java内存区域 Java虚拟机在运行程序时会把其自动管理的内存划分为以上几个区域,每个区域都有的用途以及创建销毁的时机,其中蓝色部分代表的是所有线程共享的数据区 ...

  8. Java并发指南2:深入理解Java内存模型JMM

    本文转载自互联网,侵删   一:JMM基础与happens-before 并发编程模型的分类 在并发编程中,我们需要处理两个关键问题:线程之间如何通信及线程之间如何同步(这里的线程是指并发执行的活动实 ...

  9. BAT经典面试题,深入理解Java内存模型JMM

    Java 内存模型 Java 内存模型(JMM)是一种抽象的概念,并不真实存在,它描述了一组规则或规范,通过这组规范定义了程序中各个变量(包括实例字段.静态字段和构成数组对象的元素)的访问方式.试图屏 ...

随机推荐

  1. WPF特效-粒子动画

    原文:WPF特效-粒子动画 WPF实现泡泡龙小游戏效果.     /// -Ball to Ball Collision - Detection and Handling    /// http:// ...

  2. 九款免费轻量的 AutoCAD 的开源替代品推荐

    随着各行各业的发展,CAD已经广泛应用于工业.服装.建筑以及电子产业等设计领域.AutoCAD 是一种流行的商业CAD软件,虽然很强大,但并不是免费的.因此本文推荐了几种免费重量轻的CAD工具/软件, ...

  3. centos搭建svn服务器并同步到web目录

    yum install subversion mkdir -v /root/svn cd /root/svn svnadmin create web cd web/conf/ vi passwd te ...

  4. Go 的文件系统抽象 Afero

    Afero 是一个文件系统框架,提供一个简单.统一和通用的 API 和任何文件系统进行交互,作为抽象层还提供了界面.类型和方法.Afero 的界面十分简洁,设计简单,舍弃了不必要的构造函数和初始化方法 ...

  5. 零元学Expression Blend 4 - Chapter 7 什麽?影片不再是印象中的方框框!!!看Blend 4如何把影片镶入字里

    原文:零元学Expression Blend 4 - Chapter 7 什麽?影片不再是印象中的方框框!!!看Blend 4如何把影片镶入字里 本章将教大家如何在Blend 4里新增Media El ...

  6. 解决C++项目使用sqlite中文乱码问题

    我参考的是这篇文章:https://www.2cto.com/database/201411/354891.html 理论是:sqlite使用的是UTF-8,C++中用的字符串是ascii或unico ...

  7. C#判断系统是32位还是64位

    bool type; type = Environment.Is64BitOperatingSystem; Console.WriteLine(type);

  8. Android零基础入门第41节:使用SimpleAdapter

    原文:Android零基础入门第41节:使用SimpleAdapter 通过ArrayAdapter实现Adapter虽然简单.易用,但ArrayAdapter的功能比较有限,它的每个列表项只能给一个 ...

  9. asp.net 调用带证书的webservice解决办法

    最近在朋友弄一个调整省政府政务工作流的程序.. 需要把当前的信息推送到政务网上,采用的是带证书的https webservice.. 下面说一下实现过程 第一步,引用webservice地址,删除we ...

  10. oracle rac 修改dbid和dbname

    =======================修改数据库dbid====================== 1.查看目前数据库dbid以及dbname [root@rac01 ~]# su - or ...