java内存模型个人笔记

声明:本文参考周志明著《深入理解java虚拟机》第二版

为什么要建立java内存模型?

      了解java内存模型前,先了解一下物理机 内存模型,物理机内存模型:计算机在并发地执行任务的时候,处理器至少要与内存交互,如读取运算数据,存储运算结果等,由于计算机的存储设备与处理器的运算速度有几个量级的差距,现代计算机系统都不得不加入一层读写速度尽可能快的高速缓存来作为处理器和内存之间的缓冲。这样带来的好处是处理器无需等待对内存的缓慢读写了,直接交给高速缓存来完成。但是带来的问题是缓存的一致性。在多处理器系统中,每个处理器都有自己的告诉缓存,而他们又共享一块主内存。当多个处理器的运算任务都涉及同一块内存区域时,将可能导致各自的缓存数据不一致。为了解决一致性问题,各个处理器访问缓存时都需要遵循一些协议,在读写时根据协议来进行操作。这里的内存模型可以理解为对特定的内存或高速缓存进行读写访问的过程的抽象。

      不同平台上内存模型可能不同,java虚拟机规范中试图定义一种java内存模型来屏蔽掉各种硬件和操作系统的内存访问差异,以实现让java程序在各种平台下都能达到一致的内存访问效果。

java内存模型长什么样,主要用来干什么?

      java内存模型的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节。此处的变量只包含实例字段、静态字段。和构成数组对象的元素,但不包含局部变量和方法参数,因为他们是线程私有的,不会被共享,自然不存在竞争。

       java内存模型规定了所有的变量都存储在主内存,每条线程还都有自己的工作内存,不同的线程之间无法直接访问对方工作内存的变量,线程间变量的值传递均需要通过主内存来完成。

工作内存与主内存间的八大操作

标记操作:lock/unlock:作用与主内存的变量,用来标识一个变量为一个线程独占状态/标识变量从锁定状态被释放出来

read、load操作(充要):

read操作:作用于主内存的变量,它把一个变量的值从主内存传输到线程的工作内存中,以便随后的load操作使用

load操作:作用于工作内存中的变量,他把read操作从主内存中得到的变量值放入工作内存的变量副本中

use、assign操作(作用正好相反):

use操作:作用于工作内存中的变量,他把工作内存中的变量的值传递给执行引擎。

assign操作:作用于工作内存中的变量,把一个从执行引擎中收到的值赋给工作内存中的变量

store、write操作(充要):

store操作:作用于工作内存中的变量,把工作内存中的一个变量的值传送到主内存中,以便随后的write操作使用。

write操作:作用于主内存中的变量,他把store操作传过来的变量的值放到主内存变量中。

java内存模型有哪些特征?

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

原子性:由java内存模型来直接保证的原子性变量操作包括read、load、assign、use、store、write,我们大致可以认为基本数                  据类型的访问、读写是具备原子性的(特例是long和double的非原子性协定)。更大范围的原子性操作保证由 lock和                    unlock来实现,具体反应在java代码中就是同步快——synchronized关键字。因此synchronized块之间的操作也具备原                  子性。

可见性:可见性是指当一个线程修改了共享变量的值,其他线程能够立即得知这个修改。具体实现是三个关键字:volatile、                       synchronized、final。

volatile关键字修饰的变量 是在变量修改后将新值同步回主内存,在变量读取前从主内存刷新变量值来实现

synchronized关键字是在对一个变量执行unlock之前必须把变量同不会主内存中。

final关键字是被final修饰的字段在构造器中一旦初始化完成,并且构造器没有把this关键字传递出去,那么在其他线程中就能看到fianl字段的值。

有序性:用一句话解释为,线程内有序,线程外无序。前半句是指线程内表现为串行,后半句是指指令重排序现象和工作内存和                主内存之间的同步延迟现象。java语言提供了volatile和synchronized两个关键字来保证线程之间操作的有序性。

volatile关键字本来就包含了禁止指令重排序

synchronized关键字表现为 一个变量在同一时刻只允许一个线程对其进行锁定操作

java通过以上八大操作以及volatile的相关规定就已经确定了java程序中哪些内存访问操作在并发下是安全的。和他们等效的先行发生原则,也可以用来确定一个访问在并发环境下是否安全。

先行发生规则

程序次序规则:一个线程内代码顺序执行

管程锁定规则:一个unlock操作先发生于后面对同一个锁的lock操作

volatile变量规则:对一个volatile变量的写操作先发生于后面对这个变量的读操作

线程启动规则:Thread对象的start方法先发生于此线程的每一个动作

线程终止规则:线程中的所有操作都先发生于对此线程的终止检测,我们可以通过Thread.join()方法结束、Thread.isAlive()方法                             的返回值等手段检测到线程已经终止执行。

线程中断规则:对线程intercept()方法的调用先行发生于被中断线程的代码检测到中断事件的发生,可以通过                                                         Thread.intercepted() 方法检测是否又中断发生。

对象终结规则:一个对象的初始化完成先行发生于它的finalize()方法的开始

传递性:如果操作A先行发生于操作B、操作B先行发生于操作C、那么操作A先行发生于操作C
 

注意:先行发生与时间上的先后顺序不同

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值