jvm内存模型(主存副本以及共享内存安全问题的产生以及synchronized线程安全原理和volatile关键字)

一:线程数据模型与安全:

           多核心(cpu)中,虚拟机是 一个主存 对应多个核心(cpu),一个cpu对应着多个内存副本,(可以理解为主存对应着堆内存,而内存副本对应着各个cpu的线程所属的内存,线程私有)。而一个线程取值时是从主存中取出复制到 副本中,而修改了值之后,会把修改后的值重新写入主存,在这个过程中,由于各个线程都有不同的值,因此如果多线程只读是没问题的,但是读写混合操作时,各个线程就会产生线程安全问题。

    延伸:内存副本的数据修改后,会刷新到主存中,但是这个过程会有延迟,不是立刻就刷新数据,因此,使用volatile关键字,能强制将缓存的数据更新到主存中

二:volatile 关键字:

        使用 volatile 修改变量,会强制每个要读取该变量的线程从主存中进行同步数据,保证数据是最新的。读取时会进行刷新主存操作。但是这也只能保证读取的数据是最新的,而不能使用此特性来进行数据并发安全的限制,因为变量赋值等操作在并发下不是线程安全的,因此可能多个线程已经把数据搞乱了,但是最终数据总会是一个确定的值。

      原理:编译后,volatile 会生成 Lock的字节码指令,此指令会对变量所在缓存进行锁定,多个cpu核心中的副本都保存有此变量的缓存,而 volatile 变量在修改时,会有两步操作:1.直接将缓存数据同步到主存中 2.所有其他副本缓存的数据都会失效。是否失效是通过嗅探判断 主线上 的内存是否已经失效,如果失效,会重新从主线上读取最新数据,填充到缓存行中

三:synchronized 关键字:

       synchronized 关键字基于两个实现,一个是同步方法,一个是同步代码块。共同点是 JVM基于进入和退出 Monitor对象来实现同步。代码块是使用 MonitorEnter 和 monitorExit指令实现。monitorenter是在编译后插入到同步代码块的开始位置,而monitorexit是插入到方法结束处和异常处,两指令是一一对应。任何对象都与一个monitor与之关联,当且一个monitor被持有后,将处于锁定状态,线程执行到monitorenter指令时,将会尝试获取对象所对应的monitor的所有权,即尝试获取对象的锁。

四:对象头

       synchronized用的锁是存在java对象头里的。数组对象,使用三个字宽存储对象头,非数组类型,使用两个字宽(一字宽为4字节,即32位),对象头里的 Mark Word 里默认存储对象的HashCode、分代年龄(应该至于方法区才会对此进行计数)和锁标志位

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值