java内存模型

有些人喜欢把Java内存模型和Java内存区域Java内存区域详解弄混淆,这两个是完全不同的概念。

什么是java内存模型
Java内存模型:Java内存模型(即Java Memory Model,简称JMM)本身是一种抽象的概念,并不真实存在,它描述的是一组规则或规范,通过这组规范定义了程序中各个变量(包括实例字段,静态字段和构成数组对象的元素)的访问方式,详细来说就是在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节。此处的变量与Java编程中所说的变量略有区别,它包括了实例字段、静态字段和构成数组对象的元素,但是不包括局部变量与方法参数,因为后者是线程私有的,不会被共享,自然就不存在竞争问题。
Java虚拟机规范中试图定义一种Java内存模型来屏蔽掉各种硬件和操作系统的内存访问差异,以实现让Java程序在各种平台下都能达到一致的并发效果。在此之前,主流程序语言(如C/C++等)直接使用物理硬件(或者说操作系统的内存模型),因此,会由于不同平台上内存模型的差异,导致程序在一套平台上并发完全正常,而在另外一套平台上并发访问却经常出差,因此经常需要针对不同的平台来编写程序。

硬件的效率与一致性
我们可以让计算机并发执行若干个运算任务来提高计算机处理运算能力,但实际上没有那么简单,因为所有的运算任务都不可能只靠处理器“计算”就能完成,至少与内存的交互,如读取运算数据、存储运算结果等,就是很难消除的(不能仅仅靠寄存器来解决)。由于计算机的存储设备与处理器的运算速度之间有着几个数量级的差距,所以现代计算机都不得不加入一层读写速度尽可能接近处理器运算速度的告诉缓存(Cache)来作为内存与处理器之间的缓冲:将运算需要使用的数据复制到缓存中,让运算能快速进行,当运算结束后再从缓存同步回内存之中,这样处理器就无须等待缓慢的内存读写了。
但同时又有新的问题:缓存一致性。在处理器系统中,每个处理器都有自己的高速缓存,而它们又共享同一主内存,这样就会导致各自的缓存数据不一致的情况,为了解决这个问题各个处理器访问缓存时都要遵循一些协议,在读写时要根据协议来进行操作,这类协议有MSI、MESI、MOSI、Synapse等等。
除此之外,为了使得处理器内部的运算单元能尽量被充分利用,处理器可能会对输入代码进行乱序执行优化,处理器会在计算之后将乱序执行的结果重组,保证该结果与顺序执行的结果是一致的,但并不保证程序中各个语句计算的先后顺序与输入代码中的顺序一致。类似的,Java虚拟机的即时编译器中也有类似的指令重排序优化。

主内存与工作内存
**主内存:**Java内存模型规定了所有的变量都存储在主内存中(此处的主内存与上面介绍物理硬件的主内存有所差异,此处仅是虚拟机内存的一部分,可以与物理内存类比)主内存被所有的线程共享,对于一个共享变量(比如静态变量,或者堆内存中的实例)来说,主内存中存储的是它的实例本身。
工作内存:每条线程都拥有自己的工作内存(可与前面处理器高速缓存类比),工作内存保存了该线程使用到的变量的主内存副本拷贝,线程对变量的所有操作(读取、赋值等)都必须在工作内存中进行,而不能直接读写主内存中的变量。不同的线程之间也无法直接访问对方工作内存中的变量,线程间变量值的传递都需要通过主内存来完成。

内存间交互操作
关于主内存与工作内存之间具体的交互协议,即一个变量如何从主内存拷贝到工作内存、如何从工作内存同步回主内存之类的实现细节,Java内存模型中定义了以下八种操作来完成:
lock(锁定):作用于主内存的变量,它把一个变量标识为一条线程独占的状态。
unlock(解锁):作用于主内存的变量,它把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定。
reda(读取):作用于主内存的变量,它把一个变量的值从主内存传输到线程的工作内存中,以便随后的load动作使用。
load(载入):作用于工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中。
use(使用):作用于工作内存的变量,它把工作内存中一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用到变量的值的字节码指令时将会执行这个操作。
assign(赋值):作用于工作内存的变量,它把一个执行引擎接收到的值赋值给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作。
store(存储):作用于工作内存的变量,它把工作内存中一个变量的值传送到主内存中,以便随后的write操作使用。
write(写入):作用于主内存的变量,它把store操作从工作内存中得到的变量的值放入主内存的变量中。
如果 要把一个变量从主内存复制到工作内存,就要按顺序执行read和load操作,如果要把变量从工作内存同步回主内存,就要按顺序的执行store和write操作。需要注意的是:必须按顺序执行,并没有保证必须连续执行。也就是说在read和load、store和write之间可插入其他指令。
Java内存模型还规定了在执行上述八种基本操作时必须满足如下规则:
1、不允许read和load、store和write操作之一单独出现
2、不允许一个线程丢弃它的最近的assign操作,即变量在工作内存中改变了之后必须把该变化同步回主内存
3、不允许一个线程无原因地(没有发生过任何assign操作)把数据从线程的工作内存同步回内存中
4、一个新的变量只能在主内存中“诞生”。
5、一个变量在同一个时刻只允许一条线程对其进行lock操作,但lock操作可以被同一条线程重复执行多次,多次执行lock后,只有执行相同次数的unlock操作,变量才会被解锁。
6、如果对一个变量执行lock操作,将会清空工作内存中此变量的值,在执行引擎使用这个变量前,需要重新执行load或assign操作初始化变量的值。
7、如果一个变量事先没有被lock操作锁定,则不允许对它执行unlock操作;也不允许去unlock一个被其他线程锁定住的变量。
8、对一个变量执行unlock操作之前,必须先把此变量同步回主内存中

原子性、可见性和有序性
原子性:由Java内存模型来直接保证的原子性变量操作包括read、load、assign、use、store、和write这留个,我们大致可以认为基本数据类型的访问读写时具备原子性的(long和double的非原子性协定例外)。
如果应用场景需要一个更大范围的原子性保证,Java内存模型还提供了lock和unlock操作来满足这种需求,尽管虚拟机没有把lock和unlock操作直接开放给用户使用,但却提供了更高层次的字节码指令monitorenter和monitorexit来隐式的使用这两个操作,这两个字节码指令反映到Java代码中就是同步块-synchronized关键字,因此synchronized块之间的操作也具备原子性。
可见性:当一个线程修改了共享变量的值,其他线程能够立即得知这个修改
**有序性:**Java程序中天然的有序性可以总结为一句话:如果在本线程内观察,所有的操作都是有序的;如果在一个线程中观察另一个线程,所有的操作都是无序的。前半句是指线程内表现为串行的语义,后半句是指“指令重排序”现象和“工作内存与主内存同步延迟”现象
————————————————
版权声明:本文为优快云博主「Amaranth007」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/weixin_40096176/article/details/80497137

资源下载链接为: https://pan.quark.cn/s/9648a1f24758 Java JDK(Java Development Kit)是Java编程语言的核心组件,为开发和运行Java程序提供了必要的工具和环境。JDK 8是Oracle公司推出的一个重要版本,它引入了许多新特性和改进,极大地提升了开发效率和代码质量,对开发者来说具有极高的实用价值。 本次提供的“jdk-8u251-macosx-x64.dmg”安装包是专为Mac OS X系统设计的64位版本,其中不仅包含了Java运行环境(JRE),还涵盖了丰富的开发工具,方便用户在Mac平台上进行Java程序的开发与运行。 JDK 8的关键更新和特性如下: Lambda表达式:这是JDK 8的一项重大语法创新,允许开发者使用简洁的匿名函数替代复杂的多行回调代码,从而使代码更加简洁、易读且高效。 方法引用与构造器引用:与Lambda表达式配合使用,可以更直观地引用已有的方法或构造器,进一步减少冗余代码,提升代码的可维护性。 Stream API:这是一个用于处理集合的新API,采用声明式处理方式,使集合操作(如过滤、映射和归约等)更加高效且易于理解。 日期和时间API的改进:JDK 8对日期和时间API进行了重构,引入了java.time包,包含LocalDate、LocalTime和LocalDateTime等类,替代了原有的java.util.Date和java.util.Calendar,使日期和时间的处理更加友好和灵活。 Optional类:为解决null对象导致的空指针异常问题,JDK 8引入了Optional类,它是一个容器对象,可以表示一个值存在或不存在,从而有效避免空指针异常。 接口的默认方法和静态方法:接口现在可以定义默认方法(使用default关键字)和静态方法。默认方法允许在不破坏向后
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值