7.指令重排 与 happens-before


7. 指令重排 与 happens-before

指令重排可以在 CPU 闲置(等待变量装载等)时,先执行其他指令,提高性能。分为:

  • 编译器优化重排:编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。
  • 指令并行重排:现代处理器采用了指令级并行技术来将多条指令重叠执行。如果不存在数据依赖性(即后一个执行的语句无需依赖前面执行的语句的结果),处理器可以改变语句对应的机器指令的执行顺序。
  • 内存系统重排:由于处理器使用缓存和读写缓存冲区,这使得加载(load)和存储(store)操作看上去可能是在乱序执行,因为三级缓存的存在,导致内存与缓存的数据同步存在时间差。

指令重排在单线程时可以保证串行语义一致,但多线程时可能出现问题。

JMM 能保证指令重排后,不改变程序的执行结果:

  • 单线程肯定能保证
  • 多线程需要正确同步后,可以保证

7.1 happens-before 来保证指令的运行结果

happens-before 规范用来保证两个操作之间的执行顺序。这两个操作可以是一个线程内的,也可以是多线程的。

  • 如果A happens-before B,则 A 在内存上做的操作对 B 都是可见的。

Java 中天然的 happens-before 关系:

  • 程序顺序规则:一个线程中的每一个操作,happens-before于该线程中的任意后续操作。
  • 监视器锁规则:对一个锁的解锁,happens-before于随后对这个锁的加锁。
  • volatile变量规则:对一个volatile域的写,happens-before于任意后续对这个volatile域的读。
  • 传递性:如果A happens-before B,且B happens-before C,那么A happens-before C。
  • start规则:如果线程A执行操作ThreadB.start()启动线程B,那么A线程的ThreadB.start()操作happens-before于线程B中的任意操作
  • join规则:如果线程A执行操作ThreadB.join()并成功返回,那么线程B中的任意操作happens-before于线程A从ThreadB.join()操作成功返回。

文章作者: Yu Yang
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Yu Yang !
 上一篇
内存模型 JMM 内存模型 JMM
6. Java 内存模型6.1 并发模型线程间进行通信和同步,可以通过 2 种方式的并发模型来实现: 消息传递并发模型 共享内存并发模型 Java 中,采用的是第二种:共享内存并发模型 6.2 JVM 运行时数据区 方法区 和 堆,
下一篇 
8.volatile 关键字 8.volatile 关键字
8. volatile8.0 为什么存在内存可见性问题 -> 缓存一致性问题可见性是指某线程修改了一个变量的值,新值对于其他线程是立即可见的。 为了提高代码执行速度,CPU 先把资源从内存加载到 CPU 缓存中(L1, L2等),但操
  目录