一、重排序问题(reordering)
1. 编译器指令重排序:
为了优化程序的执行效率对字节码指令进行重排序,如 Java 的 JIT 编译器。
2. 处理器指令重排序:
大多数现代微处理器都会采用将指令乱序执行(out-of-order execution,简称 OoOE 或 OOE)的方法,在条件允许的情况下,直接运行当前有能力立即执行的后续指令,避开获取下一条指令所需数据时造成的等待
肆无忌惮的重排序使得单线程内都可能出现可见性问题(即单线程内也不遵从数据依赖关系),当然,不同的处理器有不同的重排序规则。
二、共享内存的内存模型:
共享内存的内存模型因为有主内存和线程私有内存,共享变量在在这两种内存之中无法时刻保持一致,导致可见性问题。
三、Java 内存模型(JMM,Java Memory Model)
1. 什么是 JMM:
Java 的内存模型是共享内存的内存模型,它通过提供 happens-before 规则来保证可见性。它屏蔽了各种硬件和操作系统的内存模型的差异,实现跨平台。
2. JMM 的结构:
主内存:
存储共享变量,包括静态变量、成员变量和数组元素。
工作内存:
存储线程私有变量,包括方法参数、局部变量和临时变量。
3. happens-before 规则:
3.1 程序次序规则:
一个线程中的每个操作都 happens- before 于该线程中的这个操作的任意后续操作。
数据依赖关系:
as-if-serial 语义:as-if-serial 语义的意思指:不管怎么重排序,单线程的执行结果不能被改变,也就是单线程内保证了数据依赖关系。
Java 内存模型通过保证 as-if-serial 语义来保证程序次序规则,也就是单线程内的的可见性。
3.2 锁定规则:
对一个监视器锁的解锁,happens- before 于随后对这个监视器锁的加锁。
3.3 volatile 变量规则:
对一个 volatile 变量的写,happens-before 于任意后续对这个 volatile 变量的读。
3.4 传递规则:
如果 A happens- before B,且 B happens-before C,那么 A happens- before C。
3.5 线程启动规则:
Thread 对象的 start()方法 happens-before 于此线程的每一个动作。
3.6 线程中断规则:
对线程 interrupt()方法的调用 happens-before 于被中断线程的代码检测到中断事件的发生。
3.7 线程终止规则:
线程中所有操作都 happens-before 于对此线程的终止检测。
3.8 对象终结规则:
一个对象的初始化完成(构造函数执行结束)happens-before 于它的 finalize()方法的开始。
四、并发程序的三个特性:
1. 原子性:
2. 可见性:
3. 有序性:
参考:
《深入理解 Java 虚拟机》
深入理解 java 内存模型
Java 内存访问重排序的研究
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于