Java内存模型

“让计算机并发执行若干个运算任务”可以“更充分的利用计算机处理器的效能”。但是,绝大多数的运算任务都不可能只靠处理器“计算”完成,处理器至少要与内存交互,如读取运算数据、存储运算结果等,这个I/O操作是很难消除的。由于计算机的存储设备和处理器的运算速度有几个数量级的差距。于是加入一层高速缓存来作为内存与处理器之间的缓冲。
这里写图片描述


基于高速缓存的存储交互解决了处理器与内存的速度矛盾,但是引入了缓存一致性的问题。
每个处理器都有自己的高速缓存,而它们又共享同一主内存,当多个处理器的运算任务都涉及同一块主内存区域时,将可能导致各自的缓存数据不一致。为了解决一致性问题,在读写时需要根据协议来进行操作。


内存模型可以理解成在特定的操作协议下,对特定的内存或高速缓存进行读写访问的过程抽象。
不同架构的物理机器可以拥有不一样的内存模型。Java虚拟机的内存模型用来屏蔽各种硬件和操作系统的内存访问差异,以此实现Java的跨平台性。

主内存与工作内存

Java内存模型规定了:

  1. 所有的变量都存储在主内存中
  2. 每条线程还有自己的工作内存,线程的工作内存中保存了被该线程使用到的变量的主内存副本拷贝
  3. 线程对变量的所有操作必须在工作内存中进行,而不能直接读写主内存中的变量
  4. 不同的线程之间也无法直接访问对方工作内存的变量
  5. 线程间变量值的传递均需要通过主内存来完成
    这里写图片描述

内存间交互操作

主内存与工作内存之间的交互协议,即一个变量如何从主内存拷贝到工作内存,如何从工作内存同步回主内存之类的实现细节。
内存模型定义了8种操作,虚拟机实现时必须保证每一种操作都是原子的,不可再分的。(double和long类型有例外)
lock:作用于主内存变量,把一个变量标记为一条线程独占的状态。
unlock:作用域主内存变量,把一个锁定的变量释放,释放后的变量才可以被其他线程锁定。
read:作用于主内存,把一个变量从主内存传输到工作内存。
load:作用于工作内存,把read的变量放到工作内存中。
use:作用于工作内存,每当需要这个值时,就会执行这个操作。
assign:作用于工作内存,赋值。
store:作用于工作内存,把一个变量从工作内存传送到主内存。
write:把store得到的变量放入主内存。


如果把一个变量从主内存复制到工作内存,顺序地执行read和Load,
如果把一个变量同步会主内存,就顺序的执行store和write。
但是,Java内存模型只要求顺序执行,没有保证是连续执行。
如果想访问主内存中的a,b变量,可 能出现,read a, read b, load b, load a
除此之外,执行这八种操作的时候还必须满足先行发生原则。

volatile

关于volatile的另一篇文章
volatile第二个语义是禁止指令重排序优化。


指令重排序会干扰并发

Map configOptions;
char[] configText;
volatile boolean initialized;
//线程A
//模拟读取配置信息,当读取完成后将initialized设置为true以通知其他线程配置可用。
configOptions = new HashMap();
configText = readConfigFile(fileName);
processConfigOptions(configText, configOptions);
initialized = true;
//线程B
//等待initialized为true,代表线程A已经把配置信息初始化完成
while(!initialized)
    sleep();

//使用线程A中初始化好的配置信息
doSomethingWithConfig();

先行发生原则

这些“天然的”先行发生关系无须任何同步,可以直接使用。如果两个操作的关系不在此列,并且无法通过规则推导出来,就没有顺序性保障,虚拟机可以对它们随意地进行重排序。

  1. 程序次序规则:在一个线程内,按照程序代码顺序,书写在前面的操作先行发生于书写在后面的操作。
  2. 管程锁定规则:一个unlock操作先行发生于后面对同一个锁的lock操作。
  3. volatile变量规则:对一个volatile变量的写操作先行发生于后面对这个变量的读操作。
  4. 线程启动规则:Thread对象的start()方法先行发生于此线程的每一个动作。
  5. 线程终止规则:线程中的所有操作都先行发生于对此线程的终止检测,可以通过Thread.join()方法结束、Thread.alive()的返回值来检测线程是否已经终止执行。
  6. 线程中断原则:对线程interrupt()方法的调用先行发生于被中断线程的代码检测到中断事件的发生。
  7. 对象终结规则:一个对象的初始化完成先行发生于它的finalize()方法的开始。
  8. 传递性:如果操作A先行发生于操作B,操作B先行发生于操作C,那就可以得出操作A先行发生于操作C。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值