关于主内存与工作内存之间具体的交互协议,即一个变量如何从主内存拷贝到工作内存,如何从工作内存同步回主内存之类的实现细节,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. 「TJOI2013」循环格

    题目链接 戳我 \(Solution\) 我们观察发现循环格要满足每个点的入度都为\(1\) 证明: 我们假设每个点的入读不一定为\(1\),那么必定有一个或多个点的入度为0,那么则不满足循环格的定义 ...

  2. 三、Node.js-HelloWorld案例

    之前我们编写的JavaScript代码都是在浏览器中运行的,因此,我们可以直接在浏览器中敲代码,然后直接运行. 在Node,我们编写的JavaScript代码将不能在浏览器环境中执行了,而是在Node ...

  3. 基于CAS的单点登录实战(2)-- 搭建cas的php客户端

    在这之前已经搭好了CAS服务端 基于CAS的单点登录实战(1)-- 搭建cas服务器 PHP-Client php-Client是官方支持的,去官网下个最新版就好了.phpCAS 接入很简单,解压放到 ...

  4. 泛型1(一些algorithm函数)

    泛型算法本身不会执行容器的操作,它们只会运行于迭代器之上,执行迭代器的操作.因此算法可能改变容器中保存的元素,也可能在容器内移动元素,但永远不会直接添加或删除元素. 只读算法: accumulate: ...

  5. underscore里面的debounce与throttle

    throttle 策略的电梯.保证如果电梯第一个人进来后,15秒后准时运送一次,不等待.如果没有人,则待机. debounce 策略的电梯.如果电梯里有人进来,等待15秒.如果又人进来,15秒等待重新 ...

  6. Linux 安装python3.7.3 提示已经自动安装了pip和setuptools 可是使用时bash提示没有找到pip

    Linux 安装python3.7.3 提示已经自动安装了pip和setuptools 可是使用时bash提示没有找到pip 今天的任务就是找到解决办法 另外就是用布置好python3的路径

  7. shim和polyfill,前端术语

    最近项目临近发布,JS的bug大都修改完毕,终于进入了我在这家公司实习+入职为数不多的摸鱼时刻.(想想真是有点感人啊) 因为项目要兼容IE8,所以我们的代码里常常要用到 shim 以支持ES5 的相关 ...

  8. 【转】IDEA快捷键功能说明及Eclipse对应操作

    1.Ctrl+z是撤销快捷键 2.如果想恢复Ctrl+z 掉的内容,按快捷键为:Ctrl + Shift + Z.方可 3.Ctrl-H(Browse Type Hierarchy) Ctrl + A ...

  9. day--43 HTML标签和CSS基本小结

    HTML标签和CSS基本小结一:常用标签 01:块标签 p,h1--h6 ,hr ,div 02:内联标签 b,i,u,s 小提示:块标签可以嵌套内置元素或者某些块级元素,但内联元素不能包含块级元素 ...

  10. P1613 跑路

    Luogu1613 #include<bits/stdc++.h> using namespace std; const int N=65; bool G[N][N][N]; int di ...