改变执行顺序
编译器, JVM 或者 CPU 共同努力通过改变执行顺序来最求程序的执行效率.
我们通常 coding 时候, 代码的执行是有一定顺序, 这样保证我们可以完成一定逻辑, 但是在 JVM 执行代码会根据需要, 也就是最求性能来调整我们代码执行顺序.
但是这样调整顺序并不会影响程序执行的结果.
- a = 3
- b = 2
- a = a + 1;
这是上面代码的 JVM 执行的情况, 我们加载 a 然后为 a 进行赋值, 然后将其保存到内存中, 同样操作在下两条语句.
- Load a
- Set to 3
- Store a
- Load b
- Set to 2
- Store b
- Load a
- Set to 4
- Store a
我们发现执行过程中 load a 被执行了两次, 我们需要对此进行优化. 具体优化如下
- a = 3
- a = a + 1
- b = 2
- Load a
- Set to 3
- set to 4
- Store a
- Load b
- Set to 2
- Store 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 的更改对其他方法可见性.
011.JPG
来源: http://www.jianshu.com/p/5fcd7b2e7835