您的位置:首页 > 编程语言

二:并发编程-重排序

2017-01-16 00:00 183 查看
上一章说了happens-before原则和as-if-serial 语义,也举了一个单线程的例子说明happens-before仅仅是要求前一个操作的执行结果对后一个操作可见,并且前一个操作要在后一个操作之前。

同时as-if-serial语义保证了在单线程程序中,不管怎样重排序,都不会对最终结果产生影响。

as-if-serial 语义把单线程程序保护起来,遵循as-if-serial语义的编译器,runtime和处理器共同为编写单线程的程序员创造了一个幻觉,认为程序就是在顺序执行,as-if-serial 语义使单线程程序不用担心重排序的困扰,也无需担心内存可见性的问题。

既然重排序既然对单线程没有影响,我们看一下重排序对多线程有什么影响:

一个典型的例子就是在get 和set操作中,如果多线程同事去get和set如下:

class TestGetSet{

int a = 0;

boolean flag = false;

public void set(){

a=1; //1

flag = true; //2

}

public int get(){

if(flag) // 3

return a * a; //4

}

}

现在假如有两个线程,分别线程A和线程B,线程A负责进行set,线程B负责进行get,那么线程B在执行操作4的时候,能否看到线程A在操作1中对共享变量的改变,答案是不一定

由于操作1和操作2没有依赖关系,线程会对操作1和操作2进行重排序,操作3和操作4同样也没有依赖关系,也会进行重排序,那么看一下当操作1和操作2进行重排序后:



在上图中,就是操作1和操作2进行了重排序,线程A在执行的时候,先把变量设置成了true,随后线程B读取这个变量,由于条件为真,进行下一步操作,但是此刻线程A还没有把共享变量写入到主内存中,那么线程B读取到的结果就是脏数据,多线程程序的语义就被破坏了

再看一下当操作3和操作4被重排序之后:



在程序中,操作3和操作4存在控制依赖关系,当代码中存在控制依赖关系的时候,会影响到指令序列执行的并行度。为此编译器核处理器会采取猜测执行客服控制相关性对并行度的影响。已处理器的才做为例,执行线程 B的处理器可以提前读取并计算a*a,然后把计算结果临时保存在一个叫重排序缓冲的硬件缓存中。当接下来判断条件为真的时候,再把计算结果写入变量中。

从上我们可以看出来,其实就是对操作3和操作4进行了重排序,重排序在这里破话了多线程程序的语义!

在单线程的程序中,runtime和处理器遵循as-if-serial原则,即使重排序也不会对计算结果产生影响,但是在多线程中,对存在控制依赖关系的操作进行重排序,可能会改变程序的执行结果。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  as-if-srial 重排序
相关文章推荐