解释一个奇怪的并发现象

来源:互联网 发布:淘宝10公斤和面机价格 编辑:程序博客网 时间:2024/06/06 04:33

我们先看一段多线程访问数据的代码例子:

public class Test1 {    private int a=1, b=2;    public void foo(){  // 线程1         a=3;        b=4;    }    public int getA(){ // 线程2        return a;    }        public int getB(){ // 线程2        return b;    }}

上面的代码,当线程1执行foo方法的时候,线程2访问getA和getB会得到什么样的结果?大多数朋友应该能回答下面三种情况:

// 都未改变
a=1, b=2
// 都改变了
a=3, b=4
// a改变了,b未改变
a=3, b=2

那么有没有可能产生下面这种可能呢:
a=1, b=4 // b改变了,a未改变

估计会产生一种这样的疑问:怎么可能 b=4语句会先于 a=3 执行呢?其实这是一个多线程之间内存可见性(Visibility)顺序不一致的问题。有两种可能会造成上面的答案:

1) Java编译器的重排序(Reording)操作有可能导致执行顺序和代码顺序不一致。
2)从线程工作内存写回主存时顺序无法保证。

先简单解释下第一点:

假设代码有两条语句,代码顺序是语句1先于语句2执行;那么只要语句2不依赖于语句1的结果,打乱它们的顺序对最终的结果没有影响的话,那么真正交给CPU去执行时,他们的顺序可以是没有限制的。可以允许语句2先于语句1被CPU执行,和代码中的顺序不一致。

从例子中看到的两条赋值语句,并没有依赖关系,无论谁先谁后结果都是一样的,所以就可能有Reordering的情况,这种情况下,对于其他线程来说就可能造成了可见性顺序不一致的问题

再接着解释第二点:
这里写图片描述
先简单认为线程在修改一个变量时,先拷贝入线程工作内存中,在线程工作内存修改后再写回主存(Main Memery)中。
假设例子中Reording后顺序仍与代码中的顺序一致,那么接下来呢?有意思的事情就发生在线程把Working Copy Memery中的变量写回Main Memery的时刻。线程1把变量写回Main Memery的过程对线程2的可见性顺序也是无法保证的。

0 0
原创粉丝点击