(1)什么是可见性:
内存可见性(Memory Visibility)是指当一条线程修改了某个变量的值,新值对于其他线程来说是可以立即得知的。
(2)共享变量:
一个变量在多个线程的工作内存中都存在副本。
(3)主内存:
保存了程序的所有变量。
(4)工作内存:
每个线程都有自己的独立工作内存,里面保存了该线程使用的变量的副本(主内存对该变量的一份拷贝)
Java 内存模型(简称 JMM)和内存区域是不一样的东西。内存区域是指 JVM 运行时将数据分区域存储,强调对内存空间的划分,即运行时数据区(Runtime Data Area)。
内存模型是定义了线程和主内存之间的抽象关系,即 JMM 定义了 JVM 在计算机内存(RAM)中的工作方式。
注:
- 线程对共享变量的所有操作都必须从自己的工作内存中读写不能直接从主内存中读写。
- 不同线程之间不能直接访问其他线程工作内存中的变量,线程间变量值的传递需要通过主内存来完成。
在执行程序时为了提高性能,编译器和处理器常常会对指令做重排序。重排序分三种类型:
- 编译器优化的重排序。编译器在不改变单线程程序语义的前提下,可以重新安排语句的执行顺序。
- 指令级并行的重排序。现代处理器采用了指令级并行技术(Instruction-Level Parallelism,ILP)来将多条指令重叠执行。如果不存在数据依赖性,处理器可以改变语句对应机器指令的执行顺序。
- 内存系统的重排序。由于处理器使用缓存和读/写缓冲区,这使得加载和存储操作看上去可能是在乱序执行。
从 Java 源代码到最终实际执行的指令序列,会分别经历下面三种重排序:
JMM 属于语言级的内存模型,它确保在不同的编译器和不同的处理器平台之上,通过禁止特定类型的编译器重排序和处理器重排序,为程序员提供一致的内存可见性保证。
Java 编译器禁止处理器重排序是通过在生成指令序列的适当位置会插入内存屏障(重排序时不能把后面的指令重排序到内存屏障之前的位置)指令来实现的。
3.1 happens-before
从 JDK5 开始,Java 内存模型提出了 happens-before 的概念,通过这个概念来阐述操作之间的内存可见性。如果一个操作执行的结果需要对另一个操作可见(“可见”是指当一条线程修改了某个变量的值,新值对于其他线程来说是可以立即得知),那么这两个操作之间必须存在 happens-before 关系。这里提到的两个操作既可以是在一个线程之内,也可以是在不同线程之间。
例如: 对一个 volatile 域的写,happens- before 于任意后续对这个 volatile 域的读。
线程执行互斥代码的过程:
-
1)获得互斥锁
-
2)清空自己的工作内存
-
3)从主内存中拷贝最新的副本到工作内存
-
4)执行代码
-
5)将更改后的变量的值刷新到主内存
-
6)释放互斥锁



