美文网首页
java内存模型

java内存模型

作者: modou1618 | 来源:发表于2019-02-01 15:50 被阅读0次

《深入理解java内存模型》-笔记

  • java各线程共享使用主内存,通过共享内存通信
  • 重排序


    重排序.png

    编译器重排序是不影响单线程执行结果的前提下,优化语句执行顺序
    指令级重排序是依赖指令并行技术,对无数据依赖性的指令进行重排序并行执行
    内存重排序是cpu使用缓存读写,批量写入主内存。应用线程在cpu1写入数据到cpu1的缓存中,然后在cpu2执行时读取数据读取的是cpu2的缓存,此时可能cpu1的缓存未更新到主内存中或cpu2的缓存未从主内存获取最新数据。对应用来说期望是写在读前,实际结果是读在写前,好像是读写内存重排序了。

  • 内存屏障
    前一内存操作完,后一内存操作才可执行
    主要是写读屏障,写之后所有cpu缓存先刷新到主内存中,然后才能读
  • happens-before
    展现给程序员的是java语句的前后执行关系。
    内部通过禁止重排序,设置内存屏障实现。
  • 数据依赖
    存在数据依赖的语句,指令或内存操作不可被重排序,会影响执行结果。重排序是为了提高程序执行并发度,同时不可更改执行结果。
  • JMM不保证完全顺序一致性,在同步锁控制的边界点保证顺序一致,锁内部则会为提高并发效率进行重排序
  • 64位long或double数据在32位机器上,应一次总线事务只能读写32位数据,所以64位类型数据读写会分成两次总线事务读写,中间可能有其他线程更改了该数据,即64位数据读写无原子性

一 volatile

1.1 主要概念

  • volatile无法保证自增操作的原子性
    ++i包含了三个独立的操作:读取count的值,将值加1,然后将计算结果写入count。这是一个“读取 - 修改 - 写入”的操作序列,并且其结果状态依赖于之前的状态。
    自增院子性通过AtomicLong等类型,或加同步锁

  • 原子性,即使64位也保证原子性。写之后的storeload屏障,读之后的loadstore屏障保证禁止volatile读写之间禁止重排序

  • 可见性,读总是读的最新值。storeLoad屏障实现。
    写volatile变量时,storeLoad屏障刷新缓存数据到主内存中,使其他cpu缓存失效。
    读volatile变量时,重新从主内存中获取最新数据。

  • 实现类似于同步锁的效果,写=释放锁,读=获取锁。除storeLoad屏障外添加的其他内存屏障保证实现。
    volatile写之前的其他写(操作A),现在在volatile写之前刷新到主内存中。
    volatile读之后的读写(操作B)被限制在volatile读完成之后执行.
    即操作A完成后通过volatile写通知,volatile读获取通知后执行操作B
    通过添加一组内存屏障实现,见1.2节

1.2 实现说明

  • 重排序限制


    volatile重排序限制.png
  • 保守策略使用内存屏障控制重排序


    volatile写.png
volatile读.png
  • 锁能保证一组操作的并发控制,volatile只能保证对当前变量的并发访问。

二 锁

  • volatile int state;表示锁状态,保证加锁后或释放锁后,其他并发进程实时获取到最新锁状态信息。
  • cas更新锁状态,防止并发加锁
juc并发库.png

三 final

  • 通过内存屏障保证读取到的final域的值都是已经构造初始化完成的值。

相关文章

网友评论

      本文标题:java内存模型

      本文链接:https://www.haomeiwen.com/subject/leqdsqtx.html