改变执行顺序
编译器、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