【深入理解并发编程系列2】JVM内存模型

内存模型

Java原生支持多线程,这种模型是为了适配不同操作系统架构。屏蔽掉系统和底层硬件的差异。工作模型如下:

图片

JVM的内存模型是JVM定义抽象的定义。
工作内存对应的JVM哪一个模块不重要因为,不同的JVM实现,实现的也不一样。

数据八大原子操作

  1. lock: 作用于主内存的变量,把一个变量标记为一条线程独占状态。
  2. unlock:与loc相反的操作。
  3. read: 作用于主内存的变量,把一个变量从主内存传输到线程的工作内存中,以便后续的load动作。
  4. load: 作用于工作内存的操作,把read操作从主内存中得到的变量放入工作内存的变量副本中。
  5. use: 作用于工作内存的操作,把工作内存中的一个变量值传给执行引擎。
  6. assign: 作用于工作内存,把一个从执行引擎接收到的值赋值给工作内存的变量。
  7. store: 作用于工作内存,把工作内存中的一个变量的值传送到主内存中,以便随后的write。
  8. write:作用于工作内存,把store操作从工作内存中的一个变量的值传送到主内存变量中。

来:lock->read->load->use
去:assign->store->write->unlock

图片

内存可见性

关键词:MESI 协议

volatile 用于保证有序性 解决可见性问题
syncronized用于保证原子性

volatile 解决可见性问题 保证及时看到。不加的话,也有可能看到。只是不及时。
如何理解:
JVM定义的这些模型语义,不会去描述多线程程序如何执行,而是描述多线程程序于许表现出来的行为。任何执行策略,只要产生的是允许的行为,那他就是一个可以接受的策略。

图片

空循环优先级超高。

synronized可以保证内存块操作的原子性。

指令重排

图片

  • as-if-serial

  • happen-before

volatile指令重排优化

内存屏障是cpu指令,作用两个:

  1. 保证特定操作的执行顺序。
  2. 保证某些变量的可见性。(volatile的可见性)

图片

原理:内存屏障技术
ifence: 一种Load barrier读屏障。
sfence: 一种Store Barrier写屏障
mfence : 全能型屏障,具备ifence和sfence能力。
Lock前缀 Lock不是一种内存屏障,但是它能完成类似内存屏障的功能。Lock会对CPU总线和高速缓存加锁,可以理解为PUC指令的一种锁。它后面可以跟 ADD,ADC,AND,BTC,BTR,BTS,CMPXCHG,CMPXCH8B,DEC,INC,NEG,NOT,OR,SBB,SUB,XOR,XADD,and XCHG指令。

手动加内存屏障

Unsafe.fullFence
java中的可见性如何保证:
归类有两种:

  1. OrderAccess::storeLoad
    lock; addl xxxx X86架构 lock替代mfence
    java: volatile,final,syncronized,sleep
  2. 上下文切换 Thread.yield

CPU 等待唤醒。所有切换都是 park,unpark。操作系统库函数:
Linux: pthread_cond_timewait
spl.park