java内存模型中重排序

 2019-12-10 16:09  阅读(1216)
文章分类:Java Core

java内存模型中重排序

在了解重排序之前我们先来了解下java多线程之间是怎样对共享数据通信的。

当有多个线程对共享变量访问(读)的时候,我们要保证共享数据的统一就需要有jmm(java内存管理里模型)来进行管

理。比如有一个共享变量,线程A对共享变量更改之后在线程B读到的是线程A更新的值。JMM怎么控制的呢?

20191210001609\_1.png

当有线程需要访问共享变量的时候,每个线程都会拷贝一份共享共享变量的副本到本地内存,当有线程改变的

共享变量的值时,先会把变量的新改变的值保存在该线程本地内存的副本,然后更新在主内存中共享变量的值,

并更新这个共享变量的版本号。这样当其他线程访问该变量的时候,会先比较版本号,版本号对不上的话就说明

该变量被其他线程更改,这时候线程B就会更新本地内存共享变量的版本号的值。

注:这里说的本地内存并不是真的在物理空间上开辟一块内存,而是为每个线程随机开辟一块内存,用来当作共

享变量的缓冲区。

比如在一个类中声明一个变量类型为volatile。这时候该变量对所有线程可见,但是这样并不是线程安全的,因为

只保证了每个线程读的可见性,当多个线程同时对共享变量进行写操作时,还是不会达到预期的效果。

了解了上面介绍的JMM后,我们再来认识下重排序。

重排序的分类:

1、编译器优化的重排序,在单线程情况下,不改变程序运行的结果,可能会重新安排指令运行的顺序。

2、指令并行的重排序,现代的处理机为了提高cpu的利用效率。会在无数据依赖性(后面会说到这个性质)的情况下,

把对应的指令拆开执行,多少条给一个cpu执行,另外多少条给其他处理机执行。

3、内存系统的重排序,由于处理器使用缓存和读/写缓冲区,这就使得加载和存储操作可能是乱序进行的。我们的cpu

为了提高处理的效率,常常会通过读取缓冲区来处理对应的指令序列。当cpu处理一段写入内存的代码之后,其他cpu

就会处理其他的操作。这样达到了对多核cpu的最大利用效果。

20191210001609\_2.png

重排序的分析:

所谓重排序,就是当我们写一段代码之后,系统不一定根据我们我们书写的顺序执行,比如我们这样定义了一段代码:

int a=1;int b=2; int c=a+b;

这段代码的执行顺序可能是先执行了int b=2,然后执行int a=1,最后执行c=a+b;这时候数据之间就有了数据的依赖性,

会先得到a和b的值然后才会得到c的值。这样才能保证c的值是正确的。数据依赖性说白了就是指变量之间有没有运算

或者赋值。

你可能会想这样重排序之后可能并不会优化多少。那么来看下面的代码:

int a = 1;        //①
    int b=2;          //②
    if(b==2){         //③
        c=a*a;        //④
    }

这时候有四条指令,①和②之间没有关系,所以可能会发生编译器优化的重排序,③和④之间有数据依赖性,所以

③语句运行完之后才会执行语句④,但实际可能是当碰到if的时候,可能会发生指令并行的重排序,先运算出a*a的

值存在缓冲区中,当if判断为真时,直接将缓冲区的值赋给c,大大提高了效率。

无论是哪种重排序都是提高对cpu的利用。毕竟cpu是最宝贵的资源。

点赞(0)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> java内存模型中重排序

相关推荐