1. Java内存模型基础
1)并发编程的两个问题
- 线程通信:以何种机制来交换信息(共享内存、消息传递);
- 线程同步:怎么控制线程之间操作的先后顺序();
2) 内存模型的抽象结构
Java中,所有实例域、静态域和数组元素都存储在堆内存,堆内存在线程之间共享。
线程之间通信两个步骤:
- 线程A本地内存刷新到主内存;
- 线程B读取刷新后的变量;
3) 源代码到编译器的重排序
为了提高性能,编译器和处理器会对指令做重排序,三种:
- 编译器优化重排序,不改变单线程语义和执行结果的重排序;
- 指令级重排序,现代处理器采用指令并行技术,若不存在数据依赖,处理器可以改变指令顺序;
- 内存重排序,处理器使用读写缓冲区,导致加载和存储可能在乱序执行;
对于编译器重排序,JMM会禁止特定类型重排序,对于处理器重排序,JMM会要求编译器在生成指令序列时,插入特定类型内存屏障来禁止处理器重排序。
4)Happens-Before简介
- 程序顺序虽则:线程中每个操作Happens-Before任意后续操作;
- 监视器规则:解锁Happens-Before随后的加锁;
- volatile变量规则:volatile变量的写操作Happens-Before后续的读操作;
- 传递性:若A Happens-Before B,B Happens-Before C则A Happens-Before C;
Happens-Before与JMM关系:
2)重排序
1)数据依赖性
编译器和处理器不会改变存在数据依赖的两个操作的执行顺序,这里仅限与单个线程中。
2)as-if-serial语义
不管怎么重排序(单线程),不能改变程序的执行结果。