Java内存模型的基础

Java内存模型的基础

并发编程模型的(线程通信,线程同步)

线程通信

关键词:共享内存的并发模型,消息传递的并发模型,隐式通信,显示通信
通信:线程之间以某种机制进行交换信息
共享内存的并发模型:线程之间的共享程序的公共状态,通过写-读内存中的公共状态进行隐式通信。
消息传递的并发模型:线程之间没有公共状态,线程之间必须通过发送消息来显示进行通信。

线程同步

关键词:共享内存的并发模型,消息传递的并发模型,隐式同步,显示同步
同步:程序中用于控制不同线程间操作发送相对顺序的机制。
共享内存的并发模型:显示进行同步,通过显示指定某个方法或某段代码需要在线程之间互斥执行。
消息传递的并发模型:隐式进行同步,消息的发送在消息的接收之前。

注:java的并发采用的是共享内存模型—>java线程之间通信是隐式进行的,同步是显示进行的。

java内存模型抽象结构

关键词:堆内存,局部变量,方法定义参数,异常处理器参数
堆内存:包含实例域,静态域,数组元素,堆内存在线程间是共享的。
局部变量,方法定义参数,异常处理参数不会再线程之间共享,他们不会有内存可见性问题,不受内存模型影响。
JMM:Java内存模型,JMM决定一个线程对共享变量的写入何时对另一个线程可见。

Java内存模型抽象示意图如下
Java内存模型抽象示意图

Java线程之间通信示意图如下:
![Java直线线程通信(https://img-blog.csdnimg.cn/20191208205120480.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM4ODM5NzQ0,size_16,color_FFFFFF,t_70)

从源代码到指令的重排序

关键词:编译器优化重排序,指令级并行重排序,内存系统重排序
问题:重排序诞生的原因?
	提高程序性能

问题:重排序分类?
	编译器优化重排序:编译器在不改变单线程语意的前提下重新安排语句的执行顺序
	指令级并行重排序:现代处理器采用指令级并行技术将多条指令重叠执行。若不存在数据依赖性,处理器可以改变语句对应的机器指令的执行顺序。
	内存系统的重排序:处理器使用缓存和读/写缓冲区,这使得加载和存储操作看上去是乱序执行的。

问题:3种重排序的执行顺序?
	源代码-->编译器重排序-->指令级并行重排序-->内存系统重排序-->最终的指令序列
	其中编译器重排序属于编译器处理。指令级并行重排序、内存系统重排序属于CPU重排序。对于编译器重排序,JMM会禁止特定类型的编译器重排序,对于处理器重排序,JMM的处理器重排序规则会要求Java编译器在生成指令序列时,插入特定类型的内存屏障指令,通过内存屏障指令来禁止特定类型的处理器重排序。

注:JMM输入语言级别的内存模型,确保不同编译器和不同处理器平台之上,通过禁止特定类型的编译器重排序和处理器重排序来达到可见性的一致性内存。

内存屏障分类

ProcessorAProcessorB
代码a = 1;A1 x = b;A2b = 2;//B1 y = a;//B2

初始状态:a = b = 0
处理器运行执行后得到结果:x = y = 0
原因:处理器A和处理器B可以同时把共享变量写入自己的缓冲区(A1,B1)然后从内存中读取另一个共享变量(A2,B2)最后才把自己写缓存区中保存的脏数据刷新到内存中(A3,B3),由于写缓冲区仅对自己的处理器可见,它会导致处理器执行内存操作的顺序可能会与内存实际操作顺序不一致。

处理器允许重排序类型的列表

Load-LoadLoad-storeStore-StoreStore-Load数据依赖
SPARC-TSONNNYN
x86NNNYN
IA64YYYYN
PowerPCYYYYN

N不允许两个操作重排序,允许两个操作重排序
常见的处理器允许写读重排序,不允许数据依赖的重排序。其中SPARC-TSO与x86(包括x64、AMD64)拥有较强的内存模型,强内存模型带来的结果就是不允许重排序,但SPARC-TSO与x86都使用了写缓冲区,所以他们都支持写-读重排序,且也仅支持写读重排序。

注:我们常用的都是x86(包括x64、AMD64)的处理器,日常使用只需要记住该类处理器仅允许写读重排序。

内存屏障类型表

屏障类型指令示例说明
LoadLoad BarriersLoad1:LoadLoad:Load2确保Load1数据的装载优先与Load2及所有后续装载操作的装载
StoreStore BarriersStore1:StoreStore:Store2在Store2执行前,Store1此时已经对所有处理器可见
LoadStore BarriersLoad1:LoadStore:Store2在Store2执行前,Load1的操作已经完成
StoreLoad BarriersStore1:StoreLoad:Load2在Load2执行前,Store1此时已经对所有处理器可见

StoreLoad Barriers 是全能型屏障,具有以上4种屏障的效果,现代多处理器大多支持该屏障。该屏障会将写缓冲区中的数据全部刷新到内存中,相对其他屏障,执行该屏障的开销会很大。

happens-before

从JDK5开始,Java使用JSR-133内存模型。JSR-133使用happens-before概念来阐述操作之间的内存可见性。在JMM中,如果一个操作执行结果需要对另一操作可见,那这两个操作之间必须要存happens-before关系。
happens-before关系如下:
1.程序顺序规则:单线程中的每个操作都对其之后的操作可见
2.监视器规则:解锁操作必须对加锁操作可见
3.volatile变量规则:对一个volatile变量进行修改后,该volatile变量对之后的读该变量可见。
4.传递性。A happens-before B,B happens-before c 那 A happens-before C
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值