java内存模型

2018-05-07  本文已影响0人  Binarylife

注:本文仅是本人对学习资料的总结,如有不对之处请大家指出

java内存模型

有图有真相首先我们来一张图

image
这就是一个简单的JMM(java内存模型)我们可以看到

JVM内部对java内存模型的实现

image
如果所示,java内存模型把内存分为了两个区域:线程栈区堆区然后我们来明晰三个概念

硬件内存架构

软件最终还是依托与硬件,所以要了解java内存模型究竟是怎么运作的我们还需要了解底层的硬件逻辑


image

如图所示
CPU与主存的关系,处理过后的数据会放到,cpu寄存器中,再更新到cpu缓存区(这里cpu的缓存可以是多级的,因为不是专门研究硬件就不讨论了),最后更新到主存中。更新的时间是个玄学问题##Java内存模型和硬件架构之间的桥接关系
大部分内容会放在主存区,小部分才会在cpu寄存器中


image
因为这个玄学问题会引发两点

共享对象的可见性

image
来我们来假设这么一个场景线程1要更新数据,而线程二要读取更新后的数据。首先线程一更新了数据但是却没有立刻更新到主存中,而是首先更新到cpu缓存区中,这个时候线程二想要读取更新好的数据,就会去缓存中读取数据,这个时候读到的却是更新前的。这也是脏读的现象。在java中我们可以使用volatite关键字来解决这个问题,至于volatite关键字,volatite关键字保证了变量会直接刷新到主存中而不是在缓存区中,并且会直接读取主存中的数据。怎么实现线程间的可见性我们随后会讨论到

竞争现象

image
来同理我们再来看看脏写的现象,假设A和B线程同时要更新
主存中的数据,那么A和B会分别读取变量到自己的cpu缓存区,然后进行+1操作,应为这个动作是并行的所以最后flush会让主存中的数据被刷新了两次,结果不是+2而只是加一
解决这个问题,java中提供了synchronized代码块,synchronized代码块保证了同一时间只有一个数据进入竞争区,并且所有变量都会从主存区读取,当线程退出代码的时候,直接刷新主存中的数据

支持JAVA内存模型的基础原理

指令重排序
在执行程序的时候,为了提高性能会对指令进行重新排序,java通过插入内存屏障(Memory Barrier)来静止特定类型的编译器重排序和处理去重排序,为内存的可见性提供了保证。让我们来认识一下三种指令重排序方式

内存屏障(Memorry Barrier)

happen-before原则

与程序员密切相关的happen-before原则

上一篇 下一篇

猜你喜欢

热点阅读