重排序 初闻 volatile and JMM

参考深入理解Java内存模型 《深入理解Java内存模型》读书总结

1.重排序是怎么一回事?

   - 编译器排序 和 运行期重排序

   - 访问一个程序变量(对象实例字段,类静态字段和数组元素)可能会使用不同的顺序执行,

     而不是程序语义所指定的顺序执行。编译器能够自由的以优化的名义去改变指令顺序。 如果一个线程写    入值到字段a,然后写入值到字段b,而且b的值不依赖于a的值,那么,处理器就能够自由的调整它们的执行顺    序,而且缓冲区能够在a之前刷新b的值到主内存。

   不要假设指令执行的顺序,你无法预知不同线程之间的指令会以何种顺序执行。

   但是对于多线程程序,重排序可能会导致程序执行的结果不是我们需要的结果!因此,就需要我们通过“volatilesynchronize,锁等方式”作出正确的实现同步。保证happen-before

3.JMM (Java memory model)

  - Java线程之间的通信由Java内存模型(本文简称为JMM)控制,JMM决定一个线程对共享变量的写入何时对另一个线程可见。从抽象的角度来看,JMM定义了线程和主内存之间的抽象关系:线程之间的共享变量存  储   在主内存(main memory)中,每个线程都有一个私有的本地内存(local memory),本地内存中存储了该线程以读/写共享变量的副本。本地内存是JMM的一个抽象概念,并不真实存在。它涵盖了缓存,写缓冲区,寄存器以及其他的硬件和编译器优化。

线程A与线程B之间如要通信的话,必须要经历下面2个步骤:

  1. 首先,线程A把本地内存A中更新过的共享变量刷新到主内存中去。
  2. 然后,线程B到主内存中去读取线程A之前已更新过的共享变量。

3. happen-before

  //如果一个操作执行的结果需要对另一个操作可见,那么这两个操作之间必须存在happens-before关系。这里提到的两个操作既可以是在一个线程之内,也可以是在不同线程之间。

程序顺序规则:一个线程中的每个操作,happens- before 于该线程中的任意后续操作。
监视器锁规则:对一个监视器锁的解锁,happens- before 于随后对这个监视器锁的加锁。
volatile变量规则:对一个volatile域的写,happens- before 于任意后续对这个volatile域的读。
传递性:如果A happens- before B,且B happens- before C,那么A happens- before C。

 4.volatile的作用?

     与synchronize一样,都是为了线程安全!但是synchronize是锁住代码块,保证代码执行的原子性,同一时刻,只能有一个对象

     获得锁!而volatile则是通过把变量声明为volatile类型,那么就能保证每个线程任一时刻读到的都是最新的值(JMM会把该线程对应的本地内存置为无效。线程接下来将从主内存中读取共享变量

    !同时保证了写的原子性,比如,volatile int a ;  a = 2; 那么向a中写入2时,JMM会把该线程对应的本地 内存中的共享变量刷新到主内存。

    但是 ,对于volatile++ 这些复合操作就不是原子的了!

5. 本地内存 和 主内存?

     主内存     —— 即main memory。在java中,实例域、静态域和数组元素是线程之间共享的数据,它们存储在主内存中。

    本地内存 —— 即local memory。 局部变量,方法定义参数 和 异常处理器参数是不会在线程之间共享的,它们存储在线程的本地内存中。

     我们在某个线程对一个共享数据赋值,倘若不把它定义为volatile类型的话,可能不能立马写入主内存,而是写入本地内存缓冲区,这样,别的线程就不能得到最新的值!除非通过加锁!

猜你喜欢

转载自kainever7.iteye.com/blog/2201184