首先我们要知道这是两个完全不同的概念,java内存模式是java语言提出的规范,JVM运行时数据区是java虚拟机的规范;java内存模型是用来描述多线程间的特性,描述了多线程程序的合法行为,即为多线程程序定义的一套规则。JVM运行时数据区 java虚拟机包含 方法区,堆,本地方法栈,java方法栈,程序计数器,其中:方法区和堆为线程共享的,本地方法栈,java方法栈和程序计数器为线程私有的。
各区域详解 方法区:JVM用来存储加载的类信息、常量、静态变量、编译后的代码等数据,在虚拟机规范中这是一个逻辑区。具体的实现根据不同虚拟机来实现。
堆内存:内部可分为老年代、新生代,在JVM启动时就创建的,用来存放对象的实体。是垃圾回收器主要回收的目标。如果堆内存满了,就会抛出OutOfMemoryError
虚拟机栈:每个线程都有这样一个私有的空间。线程栈由多个栈帧组成。一个线程会执行一个或多个方法,一个方法对应一个栈帧,栈帧内容包含:局部变量表、操作数栈、动态链接、方法返回地址、附加信息等,栈内存默认为1M,超出则抛出StackOverflowError。
本地方法栈:和虚拟栈类似,虚拟机栈是为了执行java方法而准备的,本地方法栈是为了虚拟机使用Native本地方法而准备的。
程序计数器:记录当前线程执行字节码的位置,存储的是字节码指令地址,如果执行Native方法,则计数器值为空。每个线程都有这个空间有一个私有的空间,占用内存空间很少。CPU同一时间,只会执行一条线程中的指令。JVM多线程会轮流切换并分配CPU执行时间的方式。为了线程切换后,需要通过程序计数器,来恢复正确的执行位置。
java内存模型 java内存模型主要是为了解决多线程程序中存在的两个主要问题:可见性(主要是因为cpu高速缓存导致)和有序性(主要是因为执行重排导致的)。那么java内存模型是怎么解决这两个问题的呢?
volatile关键字 —— 解决有可见性问题 在程序中出现可见性问题的主要原因,就是使用了CPU缓存,导致在多核CPU中缓存的数据不一致性,导致共享变量没有按照我们的意图进行执行。所以volatile关键字主要有两个作用:1.禁止缓存,直接在内存中进行读取和写入数据,2.对volatile变量相关的指令不做重排操作。
Happen-Before规则 —— 解决有序性问题 有时候java虚拟机和执行程序会对指令进行一定的重排,导致程序没有按照我们想要的方式进行,这样就导致程序出现了问题,但是并非所有的指令都可以随便的改变执行位置,有一些原则是指令不可进行重排序的,这就规则也就是Happen-Before规则。
程序顺序原则:一个线程内保证语义的串行化。
volatile规则:volatile变量的写,先发生于读,这保证了volatile变量的可见性。
锁规则:解锁(unlock)必然发生在随后的加锁(lock)前。
传递性:A先于B,B先于C,那么A必然先于C
线程的start()方法先于它的每一个动作
线程的所有操作先于线程的终结(Thread.join())
线程的中断(interrupt())先于被中断线程的代码
对象的构造函数执行、结束先于finalize方法。
技术分享技术分享