重排序是指编译器和处理器为了优化程序性能而对指令序列进行从新排序的一种手段。
重排序分3种类型。java
这些重排序可能会致使线程程序出现内存可见性问题。
比方,一个线程执行两行代码:a = 1; flag = true; 而另一个线程执行if(flag){ a = 2 }。若是前者线程发生重排序,并发的时候后者线程就可能发生线程安全问题。(原本前者线程执行到a=1的时候flag仍是false呢,结果因为重排序先执行了,就致使后者线程进入了if(){}中)程序员
顺序一致性内存模型是一个被计算机科学家理想化了的理论参考模型,它为程序员提供了极强的内存可见性保证。
顺序一致性内存模型有两大特性。数据库
在概念上,顺序一致性模型有一个单一的全局内存,这个内存经过一个左右摆动的开关能够链接到任意一个线程,同时每个线程必须按照程序的顺序来执行内存读/写操做,在任意时间点最多只能有一个线程能够链接到内存。当多个线程并发执行时,全部线程的全部内存读/写操做按照调度执行串行化。编程
须要重点理解的happens-before:
为了不java程序员理解复杂的跟cpu指令相关的内存屏障来保证重排序规则,java使用了happens-before的概念来阐述操做之间的内存可见性。在JMM中,若是一个操做执行的结果须要对另外一个操做可见,那么两个操做之间必需要存在happens-before的关系。这两个操做能够在同一个线程内,也能够在不一样线程内。缓存
happens-before规则:安全
怎么理解呢?
把A happens-before B 当作 A的发生B必定是知道的。(不是说多线程中A必定要在B以前发生)多线程
什么是可见性?
各个线程虽然有本身的缓存,但各个线程在使用同一个变量进行运算以前以及运算完成以后,该变量在各个线程中的数据是一致的。并发
什么是原子性?
原子性其实就是告诉cpu不能中断,直到执行完一段指令集以后才能切换。cpu执行完时间片后的任意一个原子指令集以后,都有可能被调度器切换到去执行其余线程。属于执行的最小单元。相似于数据库事务的原子性。
数据在主内存与线程工做内存的交互,Java虚拟机规范定义了8种原子操做:锁定(lock)、解锁(unlock)、读取(read)、载入(load)、使用(use)、赋值(assign)、存储(store)、写入(write)。
读取(read)、载入(load)、使用(use)、赋值(assign)、存储(store)、写入(write)这6中操做是最基本的原子性操做。 若是想要实现更多操做组成的原子性操做,可使用关键字lock和unlock或者synchronized。app
cpu原子性的实现方式:性能
java原子性的实现方式:
循环CAS方式的特色,在低争抢的场景下,操做效率高。缺点也很明显:
voliatile关键字只保证变量的可见性,禁止指令重排序优化,不是原子性的。
实现可见性的关键字有:voliatile、synchronized(lock)、final
保证有序性的关键字有:voliatile、synchronized(lock)
参考资料: