并发编程----JMM模型,volatile,sychronized

JMM(java 内存 模型)

      JMM(java 内存模型)是一种规范,解决线程中数据不一致问题(可见性,原子性,一致性),主要解决缓存一致性问题。

     JMM模型图示:

     并发编程----JMM模型,volatile,sychronized

并发编程----JMM模型,volatile,sychronized

JMM抽象模型

并发编程----JMM模型,volatile,sychronized

多线程情况JMM模型中会产生 原子性问题,可见性问题。

有序性问题是由 1、编译器指令重拍,2、处理器指令重排 3内存系统的重排序产生的。

JMM如何解决原子性,可见性,有序性问题

采用限制处理器的优化和使用内存屏障

原子性解决方案:sychronized(monitorenter/monitorexit)

可见性解决方案:volatile、sychronized、final

有序性解决方案:volatile、sychronized

volatile关键字

        轻量级的锁,通过#lock解决可见性问题

        内存屏障解决重排序的问题

从cpu层面了解内存屏障

内存屏障的作用:防止指令重排,保证数据的可见性

cpu屏障类型:store barrier(写屏障)、load barrier(读屏障)、full barrier(全屏障)

store barrier (写屏障 storestore barrier)

强制在storestore内存屏障之前的所有指令先执行,发送缓存失效的信号。

所有在storestore内存屏障的指令之后的store指令,必须在storestore内存屏障之前的指令执行完之后再执行

并发编程----JMM模型,volatile,sychronized

load barrier 读屏障 loadloadbarrier 

 强制在loadload内存屏障之前的所有指令先执行,

所有在loadload内存屏障的指令之后的load指令,必须在loadload内存屏障之前的指令执行完之后再执行

并发编程----JMM模型,volatile,sychronized

full barrier  全屏障   store和load两者的结合就是fullbarrier

并发编程----JMM模型,volatile,sychronized

内存屏障解决的是顺序一致性问题,并不能解决缓存一致性问题,缓存一致性问题是由缓存锁即MESI完成的

编译器(JMM)层面如何解决指令重排问题? 

 

        通过volatile 关键字可以去取消编译器上的缓存和重排序。防止重排序导致可见性问题,保证编译器的优化不会影响到代码实际执行顺序。 源码中有ACC_VOLATITLE

      编译器层面将内存屏障分为四类

       loadloadbarrier      (例如  load1 loadload load2  表示load1的装载一定在load2之前  其他的内存屏障同理 )

      storestorebarrier 

      loadstorebarrier

      storeloadbarrier

内存屏障的功能:

1、确保指令重排序不会把内存屏障后面的指令排到内存屏障前面去,也不会把内存屏障前面的指令排到内存屏障后面去

2、强制对缓存的修改,会立即写到主内存里。

3、写操作会导致其他cpu的缓存无效

volatile的原子性

    volatile没有办法保证符合(如 i++)操作的原子性,可以保证单操作的原子性(如 stop = flase)

     i++ 实际上是三个操作

     多个线程同时执行

     首先getFiled   load   然后i.add  asgin   然后再去 putField store

     storea storeb storeload loada loadb  能保证 storea  与 loada的顺序 但是无法保证 storeb 插入执行的顺序

     在store 之后才会让其他可见,在store之前 没有办法改变

volatile的使用场景

使用场景:->线程的关闭

并发编程----JMM模型,volatile,sychronized

不加volatile 子线程无法结束,主线程改了stop的值,但是子线程没法得到stop为true,导致子线程无法结束

并发编程----JMM模型,volatile,sychronized

加了volatile,子线程可以结束