ConcurrentPrograming——JMM



一、什么是JMM?

即Java内存模型
主存:所有线程都共享的数据(静态变量、成员变量)
工作内存:每个线程私有的(对应局部变量)
可见性:由JVM缓存优化引起
有序性:由JVM指令重排序优化引起

二、JMM体现一下几个方面

1、可见性

保证指令不会受到CPU缓存的影响
缘由:t1、t2线程,t2线程从主存中读取数据(JIT编译器会把值缓存在线程己工作内存中,减少对主存中的访问,以提高效率),但是此时t1线程已经修改了主存中的值了,但是t2线程不会从主存中读取数据,只会在自己工作内存读取缓存的数据,每次读取的都是旧值,所以造成真实数据的不可见。

如何解决?
给变量加上volatile(修饰成员变量和静态成员变量)或者加锁,其作用是不会在缓存中读取数据了,只能在主存中读取数据,解决可见性问题。

2、原子性

保证指令不会受到上下文切换的影响(临界区代码的保护)

3、有序性

保证指令不会受到CPU指令并行优化的影响。

为什么重排序?
CPU希望对指令并行处理,调整了指令的顺序

JVM调整指令的顺序会发生指令重排,对代码进行优化以提高效率,在单线程下发生指令重排不会出现问题,在多线程下却是会影响结果的正确性。

指令重排序(为了实现指令集的并行效果)
为了让指令并行的执行,可能会调整指令的次序以达到高并发,提高处理的速度。重排序的前提是排序不能影响结果,但是多线程无法避免,可能会影响结果

三、Volatile与JMM

1、作用
Volatile可以禁止重排序,所以volatile既可以保证有序性,又可以保证可见性。
2、Volatile原理
Vola的底层实现的是内存屏障
会在volatile变量的写指令后加入一个写屏障
会在volatile变量的读指令前会加入一个读屏障
Volatile如何保证可见性?
写屏障保证该屏障之前的,对共享变量的改动,都同步到主存当中。下列代码ready加入了volatile关键字
在这里插入图片描述
读屏障保证该屏障后,对共享变量的读取,都加载的是主存中最新的数据
在这里插入图片描述
Volatile如何保证有序性?
写屏障会确保指令重排序时,不会将写屏障之前的代码排在写屏障之后。
在这里插入图片描述
读屏障会确保指令重排序时,不会将读屏障之后的代码排在读屏障之前。
在这里插入图片描述

四、总结

读屏障能保证之后的读能读到最新的结果,但不能保证读跑到前面去,如下图,t1线程先读了,任会发生指令交错。有序性也是保证自己的线程内的相关代码不被重排序。

所以Volatile能保证有序性和可见性,不能处理指令交错的问题,即无法实现原子性,而synochronized可以保证有序性、可见性、原子性(前提是保证共享变量都交给synochronized管理,才能保证原子性、有序性、可见性,因为synochronized里面的代码仍会发生重排序,synochronized会保证其代码里面的不被影响,但是有一部分在外面的话加上在synochronized里面可能会发生重排序就会造成问题)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值