java 内存模型 volatile 语义

本文参考 《深入理解JAVA虚拟机》(周志明) **第二版**,p362 ,对文中内容提炼加以总结而成。 - java内存模型的产生,是为了解决各个硬件和操作系统对内存访问的差异。 - 主要针对变量来定义各种规则,线程私有变量不算,因为不存在线程安全问题 - “二八原则”,二指两个内存,线程工作内存、 主内存。线程工作内存无法直接访问(读写)主内存,每个线程的线程工作内存也无法直接互相访问。这两个内存的交互有具体协议,即八个原子操作 - `lock: 作用于主内存,把一个变量表示为一条线程独占` `unlock: 作用于主内存,把一个处于锁定的变量释放,释放后才可以被其他线程锁定` `read:作用于主内存的变量,把主内存变量值传入工作内存,方便后面 load` `load:作用于工作内存,将read读取的值载入工作内存副本` `use:作用于工作哦内存,把工作内存的某个值传给执行引擎,虚拟机每次使用变量值则调用这个` `assign:作用于工作内存的变量,把一个从执行引擎接收到的值复制给工作内存的变量,虚拟机每次给变量复制使用这个` `store:作用于工作内存的变量,把工作内存值传给主内存 (类比read)` `write:作用于主内存的变量,把store操作从工作内存中得到的变量的值放入主内存中(类比load)` 这8个原子操作的一些规定 和 后面 volatile的某些特殊约定,共同决定了java线程安全体系。 ``` 1. (read load) (store write) 这两组操作必须按顺序执行 2. (read load) (store write)这两组操作必须完整,不能只出现read 没有load 类似这种 3. 如果执行了 assign, 则后续必须有 store write 4. 不允许无原因的(没发生过 assign),就发生 store write 5. 新变量只能在主内存中诞生 6. lock可以被一个线程执行多次,但unlock需要相同的次数 7. lock会清空工作内存中此变量的值,在执行引擎使用这个变量前,需要重新执行 load 或 assign 8. 没有lock 不可 unlock 9. unlock之前 ,必须对该变量 store write ``` synchronized 隐式的使用lock和unlock,对于7和9来说,可以保证线程间变量的可见性 `可见性:一个线程修改了这个变量的值,其他线程可以立即知道` volatile规则: `volatile能保证变量在线程之间的可见性` volatile修饰的变量具有的可见性,用8个原子操作解释为: use之前,必须 read+load,assign之后,必须 store+write `volatile能禁止指令重排序优化` 重排序优化是机器级的优化操作,用代码形象解释如下: ``` volatile boolean initialized = false; //thread A loadConfig(); initialized = true; //thread B while(!initialized){ sleep(); } doNext(); ``` 这代码意思就是 线程A先 loadConfig(),然后 initialized 为 true,线程B再去进行下面工作。如果进行重排序优化,则可能先在A线程 先执行 initiallized = true,后执行loadConfig(),导致B在 A线程 loadConfig() 之前跳出 while循环,显然不对。 volatile如何禁止重排序的呢,使用`内存屏障`。其实重排序优化是有条件的,必须前后无依赖,比如 : ``` A = A+10 A *= 2 ``` 类似这里(举个栗子,不代表任意代码) 两个语句前后依赖,就不能重排序。所谓的`内存屏障`,就是刻意制造这种依赖,致使代码不能重排序。(`具体操作 lock addl $0x0,(%esp),把ESP寄存器的值加0,显然是一个空操作,相当于做了一次 store + write,只不过啥也没改,但是你不能越过这个操作去执行下面的操作`) 从8个原子操作理解的话,即为: ``` T表示线程,所以这里在同一个线程内 A B 表示操作 V W 表示volatile变量 A1:T->V use | assign A2:T->V load | store A3:T->V read | write B1:T->W use | assign B2:T->W load | store B3:T->W read | write A1先于B1 => A3先于B3 ======== 个人理解: V = 1; (执行了 A1,A2,A3) W = 2;(执行了 B1,B2,B3) 从代码上来看,A3 先于 B3,由于不能重排序 所以 A1 一定先于 B1 ```

你可能感兴趣的:(java 内存模型 volatile 语义)