`
adofu
  • 浏览: 3981 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

JAVA内存模型(未完待续)

 
阅读更多

       最近因为小组的分享的缘故,细看了一下JAVA内存模型,猛地发现原来我一直认为应该怎么样怎么样的事情,和实时是不符合的,接下来简单的记录一下最近的感悟。

 

       在JVM 1.2之前,Java的内存模型实现总是直接操作主内存的,多线程的时候访问效率比较低下。目前的JVM,线程可以把变量保存在本地内存(比如机器的寄存器)中,而不直接在主存中进行读写,这样提高了访问效率。但造成一个结果就是如果一个线程在主存中修改了一个变量的值,而另外一个线程还继续使用它在寄存器中的变量值的拷贝,就产生了数据的不一致。

       VM系统中存在一个主内存叫:main memory,JAVA中所有的变量都是存储在这里的,所有变量共享一块内存。每个线程有自己的工作内存,叫:working memory,用来存储各个线程从main memory中的变量的拷贝。线程的所有对变量的操作都是在working memory中完成的,完成后,修改的数据会刷到main memory中。整个结构图如下:

 

线程之间的通信也是通过于主内存交互完成的(线程本身不进行通信)

 

重排序

为什么要重排序:CPU 的主频越来越高,与 cache 的交互次数也越来越多。当 CPU 的计算速度远远超过访问 cache 时,会产生 cache wait ,过多的 cache  wait 就会造成性能瓶颈

 

解决的方式:将cache分片,即将一块 cache 划分成互不关联地多个 slots ( 逻辑存储单元,又名 Memory Bank 或 Cache Bank) , CPU 可以自行选择在多个 idle bank 中进行存取。这种 SMP 的设计,显著提高了 CPU 的并行处理能力,也回避了 cache 访问瓶颈。

 

举个例子:a=1;b=2;

理想情况下,执行的顺序应该是:

cpu0->写入a=1到cache1中//A

cpu0->写入b=2到cache2中//B

如果cache1状态为忙碌的时候,cache0则需要等待

如果做过重排序的话就可以先执行B过程,这样就不会有cache wait,性能在这块就好有很好的保证

 

数据依赖性:如果两个操作访问同一个变量,且这两个操作中有一个为写操作,此时这两个操作之间就存在数据依赖性。如下面:

写后读,读后写,写后写 

这三种情况只要重排后,程序的执行结果将会改变,所有编译器是不会对这几种情况进行重排序的

说到底重排序遵循的规则就是:不管怎么排序,程序的执行结果不会改变(这正是as-if-serial的语义)

 

happen-before

语义:如果A行为发生于B行为之前,那么B行为对A行为可见

遵循的规则:

程序顺序规则:一个线程中的每个操作,happens- before 于该线程中的任意后续操作。

监视器锁规则:对一个监视器锁的解锁,happens- before 于随后对这个监视器锁的加锁。

volatile变量规则:对一个volatile域的写,happens- before 于任意后续对这个volatile域的读。

传递性:如果A happens- before B,且B happens- before C,那么A happens- before C。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics