关于主内存与工作内存之间具体的交互协议,即一个变量如何从主内存拷贝到工作内存,如何从工作内存同步回主内存之类的实现细节,java内存模型中定义了8种操作来完成,虚拟机实现时必须保证这8种操作都是原子的、不可分割的(对于long和double类型的变量来说,load、store、read跟write在某些平台上允许例外)。
8种基本操作:
  1. lock,锁定,所用于主内存变量,它把一个变量标识为一条线程独占的状态。
  2. unlock,解锁,解锁后的变量才能被其他线程锁定。
  3. read,读取,所用于主内存变量,它把一个主内存变量的值,读取到工作内存中。
  4. load,载入,所用于工作内存变量,它把read读取的值,放到工作内存的变量副本中。
  5. use,使用,作用于工作内存变量,它把工作内存变量的值传递给执行引擎,当JVM遇到一个变量读取指令就会执行这个操作。
  6. assign,赋值,作用于工作内存变量,它把一个从执行引擎接收到的值赋值给工作内存变量。
  7. store,存储,作用域工作内存变量,它把工作内存变量值传送到主内存中。
  8. write,写入,作用于主内存变量,它把store从工作内存中得到的变量值写入到主内存变量中
8种操作的规则:
  java内存模型还规定了在执行上述8种基本操作时必须满足如下规则:
  1. 不允许read和load、store和write操作之一单独出现,即不允许加载或同步工作到一半。
  2. 不允许一个线程丢弃它最近的assign操作,即变量在工作内存中改变了之后,必须吧改变化同步回主内存。
  3. 不允许一个线程无原因地(无assign操作)把数据从工作内存同步到主内存中。
  4. 一个新的变量只能在主内存中诞生。
  5. 一个变量在同一时刻只允许一条线程对其进行lock操作,但lock操作可以被同一条线程重复执行多次,,多次lock之后必须要执行相同次数的unlock操作,变量才会解锁。
  6. 如果对一个对象进行lock操作,那会清空工作内存变量中的值,在执行引擎使用这个变量前,需要重新执行load或assign操作初始化变量的值。
  7. 如果一个变量事先没有被lock,就不允许对它进行unlock操作,也不允许去unlock一个被其他线程锁住的变量。
  8. 对一个变量执行unlock操作之前,必须将此变量同步回主内存中(执行store、write)。
  有如上8种内存访问操作以及规则限定,再加上对volatile的一些特殊规定,就已经完全确定了java程序中哪些内存访问操作是在并发下安全的。
对于volatile的特殊规则:
  volatile有两个特性:1、对所有线程可见;2、防止指令重排;我们接下来说明一下这两个特性。
  可见性,是指当一条线程修改了某个volatile变量的值,新值对于其它线程来说是可以立即知道的。而普通变量无法做到这点。但这里有个误区,由于volatile对所有线程立即可见,对volatile的写操作会立即反应到其它线程,因此基于volatile的变量的运算在并发下是安全的。这是错误的,原因是volatile所谓的其它线程立即知道,是其它线程在使用的时候会读读内存然后load到自己工作内存,如果这时候其它线程进行了修改,本线程的volatile变量状态会被置为无效,会重新读取,但如果本线程的变量已经被读入执行栈帧,那么是不会重新读取的;那么两个线程都把本地工作内存内容写入主存的时候就会发生覆盖问题,导致并发错误。
  防止指令重排,重排序优化是机器级的操作,也就是硬件级别的操作。重排序会打乱代码顺序执行,但会保证在执行过程中所有依赖赋值结果的地方都能获取到正确的结果,因此在一个线程的方法执行过程中无法感知到重排的操作影响,这也是“线程内表现为串行”的由来。volatile的屏蔽重排序在jdk1.5后才被修复。原理是volatile生成的汇编代码多了一条带lock前缀的空操作的命令,而根据IA32手册规定,这个lock前缀会使得本cpu的缓存写入内存,而写入动作也会引起别的cpu或者别的内核无效化,这相当于对cpu缓存中的变量做了一次store跟write的操作,所以通过这样一个操作,可以让变量对其它cpu立即可见(因为状态被置为无效,用的话必须重新读取)。
  另外,java内存模型对volatile变量有三条特殊规则:
  a、每次使用变量之前都必须先从主内存刷新最新的值,用于保证能看见其它线程对变量的修改;
  b、每次对变量修改后都必须立刻同步到主内存中,用于保证其它线程可以看到自己的修改;
  c、两个变量都是volatile的,将数据同步到内存的时候,先读的先写;
long跟double变量的特殊规则
  对于64位的数据类型long跟double,java内存模型定义了一条相对宽泛的规定:允许虚拟机将没有被volatile修饰的64位数据操作分为两次32位的操作来进行。也就是允许虚拟机不保证64位数据load、store、read跟write这4个操作的原子性,这就是long跟double的非原子性协定。如果真的这样,当多个线程共享一个并未声明为volatile的long或者double类型的变量,并同时对他们进行读取修改,那么某些线程可能会读到一些既非初始值也不是其他线程修改值的代表了“半个变量”的数据。
  不过这种读到“半个变量”的情况非常罕见,因为java内存模型虽然允许实现为非原子的但“强烈建议”将其实现为原子操作,实际开发中,所有商用虚拟机都将其实现为原子操作,因此,这点我们并不需要担心。

2、java内存间交互操作的更多相关文章

  1. 转: 【Java并发编程】之十七:深入Java内存模型—内存操作规则总结

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/17377197 主内存与工作内存 Java内存模型的主要目标是定义程序中各个变量的访问规则, ...

  2. 【Java并发编程】:深入Java内存模型—内存操作规则总结

    主内存与工作内存 java内存模型的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节.此处的变量主要是指共享变量,存在竞争问题的变量.Java内存模 ...

  3. Java并发编程--7.Java内存操作总结

    主内存和工作内存 工作规则 Java内存模型, 定义变量的访问规则, 即将共享变量存储到内存和取出内存的底层细节  所有的变量都存储在主内存中,每条线程有自己的工作内存,工作内存中用到的变量, 是从主 ...

  4. Java内存模型

    1. 概述 多任务和高并发是衡量一台计算机处理器的能力重要指标之一.一般衡量一个服务器性能的高低好坏,使用每秒事务处理数(Transactions Per Second,TPS)这个指标比较能说明问题 ...

  5. Jvm基础(2)-Java内存模型

    Jvm基础(2)-Java内存模型 主内存和工作内存 Java内存模型包括主内存和工作内存两个部分:主内存用来存储线程之间的共享变量:而工作内存中存储每个线程的相关变量. 如下图所示: 需要注意的是: ...

  6. java内存模型分析2

    不同线程之间无法直接访问对方工作内存中的变量,线程间变量值的传递均需要在主内存来完成,线程.主内存和工作内存的交互关系如下图所示,和上图很类似. 这里的主内存.工作内存与Java内存区域的Java堆. ...

  7. Java内存模型(转载)

    1. 概述 多任务和高并发是衡量一台计算机处理器的能力重要指标之一.一般衡量一个服务器性能的高低好坏,使用每秒事务处理数(Transactions Per Second,TPS)这个指标比较能说明问题 ...

  8. 第十二章 Java内存模型与线程

    Java内存模型(Java Memory Model,JMM): 主内存与工作内存:Java内存模型主要是定义程序中各个变量的访问规则.Java内存模型规定了所有的变量都存储在主内存(Main Mem ...

  9. Java 多线程(六)之Java内存模型

    目录 1. 并发编程的两个问题 2 CPU 缓存模型 2.1 CPU 和 主存 2.2 CPU Cache 2.3 CPU如何通过 Cache 与 主内存交互 2.4 CPU 缓存一致性问题 3 Ja ...

随机推荐

  1. angular formBuilder

  2. C# 根据论文 像素差异算法【个人实验还是比较好使的】

    论文地址:http://www.docin.com/p-1081596986.html 具体代码: 我转YUV,再通过上面的论文的方式比较近. YVU 介绍:https://blog.csdn.net ...

  3. xp/win7中系统安装memcached服务,卸载memcached服务,以及删除memcached服务

    1.安装到系统服务中: 在doc中:执行此软件 memcached.exe -d install(如果提示错误,要找到cmd.exe用管理员身份打开) 2.卸载: 在doc中:执行此软件 memcac ...

  4. 【bzoj5093】 [Lydsy1711月赛]图的价值 组合数+斯特林数+NTT

    Description "简单无向图"是指无重边.无自环的无向图(不一定连通). 一个带标号的图的价值定义为每个点度数的k次方的和. 给定n和k,请计算所有n个点的带标号的简单无向 ...

  5. 洛谷P1963 [NOI2009]变换序列(二分图)

    传送门 我可能真的只会网络流……二分图的题一点都做不来…… 首先每个位置有两种取值,所以建一个二分图,只要有完美匹配就说明有解 考虑一下每一个位置,分别让它选择两种取值,如果都不能形成完美匹配,说明无 ...

  6. ORA-03113 : end-of-file on communication channel

    现象一: 数据库startup时,出现数据库无法正常mount,并报ORA-03113错误. SQL> startup ORACLE instance started. Total System ...

  7. ant实例

    <?xml version="1.0" encoding="UTF-8" ?> <project name="javaTest&qu ...

  8. 关于python中的round()和javascript中的round()的比较

    ps:python的round()和javascript的round()的比较: javascript:Math.round():正常的标准舍入,就像我们学的数学课本上面的规则 python:pyth ...

  9. HDU-2063(二分图匹配模板题)

    过山车Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submissi ...

  10. QQ在线状态的使用

    在网页中显示QQ在线状态并点击后发起对话,是很多门户网站常见的一个功能,这两天就碰到这样一个.原以为很简单,结果还是折腾了半天,虽然是个小问题,但也值得记录一下. 按以前的经验,网上有很多QQ在线代码 ...