手记

java 的内存模型(Java Memory Model)

改变执行顺序

编译器、JVM 或者 CPU 共同努力通过改变执行顺序来最求程序的执行效率。
我们通常coding 时候,代码的执行是有一定顺序,这样保证我们可以完成一定逻辑,但是在 JVM 执行代码会根据需要,也就是最求性能来调整我们代码执行顺序。
但是这样调整顺序并不会影响程序执行的结果。

a = 3
b = 2
a = a + 1;

这是上面代码的 JVM 执行的情况,我们加载 a 然后为 a 进行赋值,然后将其保存到内存中,同样操作在下两条语句。

Load aSet to 3Store a

Load bSet to 2Store b

Load aSet to 4Store a

我们发现执行过程中 load a 被执行了两次,我们需要对此进行优化。具体优化如下

a = 3
a = a + 1

b = 2
Load aSet to 3set to 4Store a

Load bSet to 2Store b

这些具体优化工作是 JVM 中完成的。

可见性

多线程的中一致性的表现,又叫做并发


007.JPG

我们看最上面一层 core 这里表示有 4 个 cpu,每一个 cpu 都有一个 registers(注册机),然后就是 L1 cache 一级缓存,虽然不大因为 cpu 直接从这里读取内存所以这里非常快。然后就是 L2 二级缓存这里就是两个 core 来共享的。到了 3L 缓存就是所有 core 共享的内存区域。离 cpu 越远的缓存会访问速度降低同时容量变大。

public class FieldVisibility{  int x = 0;  public void writerThread(){
    x = 1
  }  public void readerThread(){    int r2 = x;
  }
}

这里创建一个 FieldVisibility 类,初始化 x = 0,让后提供两个方法分别在不同的线程对 x 进行读写操作。


008.JPG

然后创建两个 FieldVisibility 的实例分别调用读和写方法来读写 x。

009.JPG

当我们一个实例调用 writerThread 方法来修改 x 的值为 1,x = 1 仅会保存在 local cache 本地缓存,而不会更新到 shared cache (共享缓存),所以当另一个实例调用 readerThread 来获取 x 的值,依旧得到是 0 而不是 1.

这就是字段可见性问题。

public class FieldVisibility{  volatile int x = 0;  public void writerThread(){
    x = 1
  }  public void readerThread(){    int r2 = x;
  }
}

010.JPG

当我们用关键字 volatile 修饰字段 x 时,当 x 发生变化会更新共享缓存,这样就保证 x 的更改对其他方法可见性。




作者:zidea
链接:https://www.jianshu.com/p/5fcd7b2e7835


0人推荐
随时随地看视频
慕课网APP