此文已由作者赵计刚授权网易云社区发布。

欢迎访问网易云社区,了解更多网易技术产品运营经验。


注:本文主要参考自《深入理解Java虚拟机(第二版)》和《深入理解Java内存模型》

1、Java内存模型(JMM)

Java内存模型的主要目标:定义在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节。

注意:上边的变量指的是共享变量(实例字段、静态字段、数组对象元素),不包括线程私有变量(局部变量、方法参数),因为私有变量不会存在竞争关系。

1.1、内存模型就是一张图:


说明:

  • 所有共享变量存于主内存

  • 每一条线程都有自己的工作内存(就是上图所说的本地内存)

  • 工作内存中保存了被该线程使用到的变量的主内存副本

注意:

  • 线程对变量的操作都要在工作内存中进行,不能直接操作主内存

  • 不同的线程之间无法直接访问对方的工作内存中的变量

  • 不同线程之间的变量的传递必须通过主内存

类比:(注意:主内存与工作内存只是一个概念,与堆栈内存没有关系,下边的类比只是帮助理解)

  • 主内存:对应于Java堆中的对象实例数据部分(注意:堆中还保存了对象的其他信息,eg.Mark Word、Klass Point和用于字节对其补白的填充数据)

  • 工作内存:对应于栈中的部分区域

1.2、8条内存屏障指令:

下面只列出6条与之后内容相关的,其余的查看《深入理解Java虚拟机》

  • lock:作用于主内存,把一个变量标识为一条线程独占的状态

  • unlock:作用于主内存,把一个处于锁定的变量解锁

下边四条是与volatile实现内存可见性直接相关的四条(store、write、read、load)

  • store:把工作内存中的变量的值传送到主内存中

  • write:把store操作从工作内存中得到的变量值放入到主内存的变量中

  • read:把一个变量的值从主内存中传输到线程的工作内存

  • load:把read操作从主内存中获取到的变量值放入工作内存的变量中去

注意:

  • 一个变量在同一时刻只允许一条线程对其进行lock操作

  • lock操作会将该变量在所有线程工作内存中的变量副本清空,否则就起不到锁的作用了

  • lock操作可被同一条线程多次进行,lock几次,就要unlock几次(可重入锁)

  • unlock之前必须先执行store-write

  • store-write必须成对出现(工作内存-->主内存)

  • read-load必须成对出现(主内存-->工作内存)

2、变量对所有线程的可见性

可见性:线程1对共享变量的修改能及时被线程2看到

2.1、共享变量不可见的原因

  • 共享变量更新后的值没有在工作内存和主内存之间及时更新

  • 线程交错执行

  • 指令重排序结合线程交错执行

2.2、实现共享变量及时更新的措施

线程1修改过共享变量后,将共享变量刷到主内存,然后,线程2从主内存读取该共享变量,将该共享变量载入到工作内存中

注意:在短时间内的高并发情况下,如果发生下列三种情况,则线程2就读不到线程1修改过的最新的值了,

  • 可能线程1根本来不及将修改过后的共享变量刷到主内存(这个时间非常短,但是还是有)的时候,线程2就已经读取了原有的主内存变量到其工作内存中。

  • 可能线程1虽然将修改过后的值刷到了主内存中,但是线程2的工作内存中的变量副本还没来得及从CPU刷新回来,所以线程2读取到的还是原来的工作内存中的变量副本

  • 可能线程1根本来不及将修改过后的共享变量刷到主内存的时候,同时,线程2的工作内存中的变量副本还没来得及从CPU刷新回来

注意:工作内存中的变量副本在使用之后,不会立刻消失掉,会一直存在,这样其值也一直不变,直到对其进行写操作或数据从CPU中刷新回来(类比volatile-read的作用)。

2.3、指令重排序:代码书写顺序与实际执行顺序不同(编译器或处理器为提高程序性能做的优化)

eg.

书写代码的顺序如下:

1         int a = 12;
2         int b = 13;
3         int c = a+b;

可能实际执行代码的顺序如下:

1         int b = 13;
2         int a = 12;
3         int c = a+b;

总结:本文大概介绍了一下Java内存模型以及与共享变量可见性的一些概念,为下边的volatile做准备。

免费领取验证码、内容安全、短信发送、直播点播体验包及云服务器等套餐

更多网易技术、产品、运营经验分享请点击

相关文章:
【推荐】 BigData-‘基于代价优化’究竟是怎么一回事?
【推荐】 Regular进阶: 跨组件通信
【推荐】 FUI- 我离钢铁侠还差几步?

Java内存模型与共享变量可见性的更多相关文章

  1. 附1 Java内存模型与共享变量可见性

    注:本文主要参考自<深入理解Java虚拟机(第二版)>和<深入理解Java内存模型> 1.Java内存模型(JMM) Java内存模型的主要目标:定义在虚拟机中将变量存储到内存 ...

  2. Java内存模型JMM与可见性

    Java内存模型JMM与可见性 标签(空格分隔): java 1 何为JMM JMM:通俗地讲,就是描述Java中各种变量(线程共享变量)的访问规则,以及在JVM中将变量存储到内存和从内存中读取变量这 ...

  3. 02 | Java内存模型:看Java如何解决可见性和有序性问题

    什么是 Java 内存模型? 导致可见性的原因是缓存,导致有序性的原因是编译优化,那解决可见性. 有序性最直接的办法就是禁用缓存和编译优化,但是这样问题虽然解决了,我们程序的性能可就堪忧了.   合理 ...

  4. 【并发编程】一文带你读懂深入理解Java内存模型(面试必备)

    并发编程这一块内容,是高级资深工程师必备知识点,25K起如果不懂并发编程,那基本到顶.但是并发编程内容庞杂,如何系统学习?本专题将会系统讲解并发编程的所有知识点,包括但不限于: 线程通信机制,深入JM ...

  5. java内存模型及分块

    转自:http://www.cnblogs.com/BangQ/p/4045954.html 1.JMM简介 2.堆和栈 3.本机内存 4.防止内存泄漏   1.JMM简介   i.内存模型概述 Ja ...

  6. Java内存模型(转载)

    本文章节: 1.JMM简介 2.堆和栈 3.本机内存 4.防止内存泄漏 1.JMM简介 i.内存模型概述 Java平台自动集成了线程以及多处理器技术,这种集成程度比Java以前诞生的计算机语言要厉害很 ...

  7. java内存模型一

    Java平台自动集成了线程以及多处理器技术,这种集成程度比Java以前诞生的计算机语言要厉害很多,该语言针对多种异构平台的平台独立性而使用的多线程技术支持也是具有开拓性的一面,有时候在开发Java同步 ...

  8. Java内存模型JMM 高并发原子性可见性有序性简介 多线程中篇(十)

    JVM运行时内存结构回顾 在JVM相关的介绍中,有说到JAVA运行时的内存结构,简单回顾下 整体结构如下图所示,大致分为五大块 而对于方法区中的数据,是属于所有线程共享的数据结构 而对于虚拟机栈中数据 ...

  9. Java-JUC(二):Java内存模型可见性、原子性、有序性及volatile具有特性

    1.Java HotSpot JVM运行时数据区 Java内存模型即Java Memory Model,简称JMM.JMM定义了Java 虚拟机(JVM)在计算机内存(RAM)中的工作方式.JVM是整 ...

随机推荐

  1. Ajax在jQuery中的应用 (4)向jsp提交表单数据

    ajax技术带给我们的是良好的用户体验,同时,使用jquery可以简化开发,提高工作效率. 下面就介绍一下大致的开发步骤. 工具/原料 本文中使用的是 jquery-1.3.2.min.js 方法/步 ...

  2. 数位dp小结

    数位dp其实就是一种用来求区间[l, r]满足条件的数的个数.数位是指:个十百千万,而在这里的dp其实相当于暴力枚举每一位数. 我们通过把l, r的每位数分解出来,然后分别求r里满足条件的数有多少,l ...

  3. python报错ModelNotFoundError

    很可能是因为工作目录并不在sys.path中,系统无法默认的找到您的脚本文件,通过以下命令可以解决该问题: >>> import sys>>> sys.path.a ...

  4. php 操作redis 以及几个常用命令

    redis-cli -h host -p port -a password 首次进入redis 进行绑定ip和端口号   del key 删除指定key   exists key 检查指定key是否存 ...

  5. 已经安装了客户端,但是cmd输入sqlcmd报错:Sqlcmd:Error:Connection failure.SQL Native Client is not installed correctly

    以前安装了sqlserver2008,没有卸载掉,后面又安装了sqlserver2014,所以系统环境变量中既有2008的环境变量的配置,又有2014的环境变量的配置,所以在终端输入sqlcmd时报错 ...

  6. 4-具体学习git--分支

    图形的方式显示日志:git log --oneline --graph 两种方式建立分支: 1.git branch dev,建立一个dev的分支 git branch 查看分支有哪些,星号在当前分支 ...

  7. IntelliJ IDEA 2017版 编译器使用学习笔记(九)(图文详尽版);IDE使用的有趣的插件;IDE代码统计器;Mybatis插件

    一.代码统计器,按照名字搜索即可,在file===setting------plugin 使用右键项目:点击自动统计 二.json转实体类 三.自动找寻bug插件 四.Remind me工具 五.检测 ...

  8. Vue、 React比较

    关键词:MVVM(Model-View-VIewModel)数据模型双向绑定.视图的数据变化会同时修改数据资源,数据资源的变化也会立刻反应到视图View上. 一.vue.js vue是一套构建用户界面 ...

  9. celery 4.1下报kombu.exceptions.EncodeError: Object of type 'bytes' is not JSON serializable 处理方式

    #python代码如下 from celery import Celeryimport subprocess app = Celery('tasks', broker='redis://localho ...

  10. Jersey RESTful WebService框架学习(五)使用@BeanParam

    第一步:定义一个实体类 注意:实体类的属性需要加上FormParam注解 public class User { @FormParam("name") private String ...