JMM(Java内存模型)和voltile

什么是JMM,为什么要有JMM,JVM和JMM的关系。

JMM是Java语言级别的内存模型抽象规范,是围绕着在并发过程中如何处理原子性,可见性和有序性建立的。

不同硬件平台的内存模型是不一致的,Java语言的特性是跨平台的。为了让同一份Java语音可以运行在不同的硬件平台上,就需要一个统一的内存模型来屏蔽掉硬件和操作系统对内存访问的差异,同时也为了提供给程序员一个适合开发的内存模型而不需要去关心硬件的具体实现。

JVM是JMM在不同硬件平台上的实现(但是JVM不仅仅是JMM的实现,不要搞混)。

JMM规范

JMM的主要目标是定义程序中变量的访问规则,即从内存中读取变量和写入变量到内存中这些底层细节。(变量:指的是线程共享变量,不是私有变量,例如实例字段,静态字段和构成数组对象的元素)

规定的变量访问规则如下:

1、规定变量存放在主内存中

2、每个线程有自己的工作内存,线程工作内存互相不可见,线程访问变量只能通过工作内存,将变量从内存中拷贝到工作内存中,再进行操作

3.线程之间变量值的传递均需要通过主内存完成。

主内存:可以理解为物理意义上的内存,属于JVM内存的一部分,可以强行对应到运行时数据区域的堆。

工作内存:可以类比为CPU高速缓存或寄存器,可以强行对应到虚拟机栈中的部分区域(本地变量表,操作数栈等)

关于主内存和工作内存之间具体的交互协议,Java内存模型定义了8种操作,但是这8种操作不便于理解,但是可以和先行发生原则等价,具备先行发生关系的,会有顺序性保障,无须同步。

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

管程锁定规则:一个unlock操作先行发生于对后面(时间上)的同一个所的lock操作

volatile规则:对一个volatile变量的写操作先行发生于后面(时间上)对这个变量的读操作

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

线程终止规则:Thread对象的所有操作都先行发生于对此线程的终止检测,即(Thread.join方法和isAlive方法)

线程中断规则:对线程interrupt方法的调用先行发生于被中断线程的代码检测到中断时间的发生

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

传递性:A先行发生于B,B先行发生于C,那么A先行发生于C

Volatile

在对volatile关键字赋值后会插入一条lock前缀指令,这个操作相当于内存屏障(指重排序是不能把后面的指令排序到内存屏障之前的位置)。关键在于lock前缀,在查询IA32手册,该指令的作用是本CPU的缓存写入到内存中,该写入动作会引起其它CPU缓存无效(缓存一致性协议),这样就可以让前面的volatile变量的修改对其它CPU立即可见(至于里面的细节可以参考我的另一篇文章:缓存一致性协议和volatile)。

禁止重排序也是一样的原理,指令重排序是不会对有依赖的指令进行重排序(这样才能保证正确的执行结果),lock前缀指令把修改同步到内存中意味着之前所有操作都执行完毕,以此不会发生重排序。

原子性:指一个操作或一段操作同一时间只能有一个线程来执行。Java除了对基本数据类型的访问读写保证了原子性,还提供了monitorenter和monitorexit来隐式使用同步操作,对应到Java语言就是synchronized

可见性

可见性指一个线程修改变量之后,其它线程能立即得知这个修改。除了volatile之外,synchronized和final也可以实现可见性,同步块是先行发生原则保证的,而final关键字的可见性是指先执行问构造器,再暴露指针,避免this引用逃逸。

有序性

如果在本线程内的操作都是有序的,如果在另一个线程观察另一个线程,所有的操作都是无序的。

Java提高volatile和synchronized两个关键字保证线程之间的有序性。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值