Java Memory Model - Java内存模型

it2022-05-06  0

       Java虚拟机规范定义了Java内存模型(Java Memory Model,JMM)来屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的内存访问效果。JMM本身是一种抽象的概念并不真实存在,它描述的是一组规则或规范,通过这组规范定义了程序中各个变量(包括实例字段,静态变量和构成数组对象的元素)的访问方式。

 

一、主内存和工作内存

       由于JVM运行程序的实体是线程,而每个线程创建时JVM都会为其创建一个工作内存(有些地方成为栈空间),工作内存是每个线程的私有数据区域,而Java内存模型中规定所有变量都存储在主内存,主内存是共享内存区域,所有线程都可以访问,但线程对变量的操作(读取赋值等)必须在工作内存中进行,首先要将变量从主内存拷贝到自己的工作内存空间,然后对变量进行操作,操作完成后再将变量写回主内存,不能直接操作主内存中的变量,各个线程中的工作内存中存储着主内存中的变量副本拷贝,因此不同的线程间无法访问对方的工作内存,线程间的通信(传值)必须通过主内存来完成。如下图:

二、原子性、可见性、有序性

      Java内存模型是围绕着在并发过程中如何处理原子性、可见性和有序性三个特征建立。

2.1 原子性

      由Java内存模型来直接保证的原子性变量操作包括read、load、assign、use、store和write,我们大致可以认为基本数据类型的访问读写是具备原子性的。如果应用场景需要一个更大范围的原子性保证,JMM还提供了lock和unlock操作来满足这种需求,synchronized关键字之间的代码块也具备原子性。

2.2 可见性

      可见性是指当一个线程修改了共享变量的值,其他线程能够立即得知这个修改。JMM主要是通过volatile来保证多线程操作时变量的可见性,而普通的变量不能保证这一点。

2.3 有序性

        如果在本线程内观察,所有的操作都是有序的;如果在一个线程中观察另一个线程,所有的操作都是无序的。JMM提供了volatile和synchronized两个关键字来保证线程之间操作的有序性。volatile本身包含了指令重排语义,而synchronized决定了同一个锁两个同步块只能串行地进入。

 

三、先行发生原则

      要想保证执行操作B的线程看到操作A的结果(无论A和B是否在同一个线程中执行),那么在A和B之间必须满足Happens-Before关系,否则JVM可以对它们任意地重排序。

      Java内存模型是通过各种操作来定义的,包括对变量的读/写操作,监视器的加锁和释放操作,以及线程的启动和合并操作。JM为程序中所有的操作定义了一个偏序关系,称之为Happens-Before。

Happens-Before的规则包括:

程序顺序规则:如果程序中操作A在操作B之前,那么在线程中A操作将在B操作之前执行。

监视器锁规则:在监视器锁上的解锁操作必须在同一个监视器锁上的加锁操作之前执行。

volatile变量规则:在volatile变量的写入操作必须在对该变量的读操作之前执行。

线程启动规则:在线程上对Thread.Start的调用必须在该线程中执行任何操作之前执行。

线程结束规则:线程中的任何操作都必须在其他线程检测到该线程已经结束之前执行,或者从Thread.join中成功返回,或者在调用Thread.isAlive时返回false。

中断规则:当一个线程在另一个线程上调用interrupt时,必须在被中断线程检测到interrupt调用之前执行(通过抛出InterruptedException或者调用isInterrupted和interrupted)。

终结器规则:对象的构造函数必须在启动该对象的终结器之前执行完成。

传递性:如果操作A在操作B之前执行,并且操作B在操作C之前执行,那么操作A必须在操作C之前执行。

 

Author:忆之独秀

Email:leaguenew@qq.com

注明出处:https://blog.csdn.net/lavorange/article/details/97618711


最新回复(0)