本篇将带你入门学习JVM中的内存模型。
注意区分Java内存模型和Java内存结构!
Java内存结构是涉及方法区、堆、虚拟机栈、本地方法栈、计数器等概念。
Java内存模型是涉及线程、本地内存、主内存、共享变量等概念。
每个工作线程都有自己独占的本地内存,本地内存中存储的是私有变量以及共享变量的副本,使用一定机制来控制本地内存和主存之间读写数据时的同步问题。
将工作线程和本地内存具象为线程栈(thread stack),将主存具象为堆(heap)
基本数据类型变量,如int、char等,总是存储在线程栈中。
对象类型变量,引用本身存储在线程栈上,引用指向的对象存储在堆中。
Java线程模型中的线程栈和堆都是对物理内存的抽象,可以让开发者开发过程中只需关心线程栈和堆等而不用关心更下层的CPU缓存、寄存器等等
由于工作线程大部分情况下都是在读取本地内存,那么对本地内存的速度要求更高,所以本地内存大部分是用寄存器、CPU缓存来实现。而堆需要存储大量的对象,需要更大容量,所以更经常是用主存实现。
线程通信中可能存在的问题:
可见性问题:A修改了x,但是B不知道,读取的还是之前的x
原子性问题:A和B同时都将x+1,那么主存中的x应该是要+2
并发三要素:
- 可见性:当一个线程修改共享变量的值,其他线程需要能立刻得知这个修改
- 原子性:一个操作是不可中断的,要么全部执行成功,要么全部执行失败
- 有序性:指令重排但不能影响最终结果的正确性
可见性、原子性可以使用锁来保证
可见性、有序性可以使用volatile关键字来保证
Happens-Before原则:
对于两个操作A和B,这两个操作可以在不同的线程中执行。如果A比B先执行,那么可以保证当A操作执行完后,A操作的执行结果对B操作是可见的。
Happen-Before原则一共有八个规则,只需满足其中一个规则基本保证并发中的可见性
Happen-Before原则中比较常见的三个规则:
- 程序顺序原则:程序按照书写顺序执行
- 锁定原则:即使用锁
- volatile变量原则:即使用volatile关键字
参考:
- B站up主 寒食君 关于JVM内存模型讲解的视频:视频链接