高效并发 第一节:java内存模型(JVM笔记)

 2019-12-10 15:55  阅读(901)
文章分类:Java Core

高效并发 第一节:java内存模型(JVM笔记)

20191210001421\_1.png

java虚拟机规范试图定义一种java内存模型(JMM)来屏蔽掉各种硬件和操作系统的内存访问差异,让java程序在各平台都能达到一致性的内存访问效果。

主内存与工作内存

java内存模型的主要目标是定义程序中各个变量的访问规则,即在虚拟机中将变量存储到内存和从内存中取出变量这样的底层细节。
这里所说的变量包括

  1. 实例字段
  2. 静态字段
  3. 构成数组的元素

不包括局部变量和方法参数,这些事线程私有的,不会被共享。

java内存模型规定所有的存储都存储在主内存中,每条线程还有自己的工作内存,线程的工作内存保存了该线程使用到的变量的主内存副本拷贝,线程对变量的所有操作(读取,赋值)都必须在工作内存中进行,而不能直接读写主内存中的变量。不同线程直接无法访问对方内存中的变量,线程间变量传递均需通过主内存完成,线程,主内存,工作内存关系如下:

20191210001421\_2.png

内存间交互操作

关于主内存与工作内存具体交互协议,即变量如何从主内存拷贝到工作内存,如何从工作内存同步回主内存的实现细节,java内存模型定义了8中操作完成,虚拟机实现时必须保证每一种操作是原子的,不可再分。

  1. locak(锁定):作用于主内存变量,它把一个变量标识为一个线程独占状态
  2. unlock(解锁):作用于主内存,将一个处于锁定状态的变量释放,释放后的变量才能被其他线程锁定
  3. read(读取):作用于主内存变量,它将一个变量的值从准内存传输到线程的工作内存中,以便随后load动作使用
  4. load(载入):作用于工作内存,将read操作读取的变量放入到工作内存变量的副本中
  5. use(使用):作用于工作内存,将工作内存的一个变量的值传递给执行引擎,每当虚拟机遇到一个需要使用到变量的值得字节码指令时会执行这个操作
  6. assign(赋值):作用于工作内存,它把一个从执行引擎接收到的值赋给工作内存的变量,每当虚拟机遇到一个给变量赋值的字节码指令时执行这个操作
  7. store(存储):作用于工作内存,将工作内存一个变量传送到主存,以便随后Write操作使用
  8. write(写入):作用于主内存,他把一个从工作内存中得到的变量值当如主内存变量中

java内存模型还规定了执行以上8种动作时候必须满足以下条件:

  1. 不允许read和load,store和Write操作之一单独出现,即不允许一个变量从主存读取了但工作内存不接受,或是工作内存发起了store操作但是主存不接受的情况
  2. 不允许一个线程丢弃了它最近的assign操作,即变量在工作内存被赋值但是没有把它同步回主存
  3. 不允许一个线程无原因的把数据从工作内存同步回主存
  4. 一个新的变量只能在主存中诞生,不允许工作内存中直接使用一个未被初始化的变量
  5. 一个变量在同一时刻只允许一个线程对其进行lock操作,单lock可以被同一个线程执行多次,多次执行lock后,只有执行相同次数的unlock才能解锁
  6. 如果对一个变量进行lock,那么将会清空工作内存中此变量的值,在执行引擎使用这个变量前,需要重新执行load或者assign操作初始化变量的值
  7. 如果一个变量实现没有被lock,则不允许对他执行unlock,也不允许unlock一个被其他线程锁住的变量
  8. 对一个变量执行unlock操作前,必须把它通不会主存中(store,write)

对于volatile型变量的特殊规则

volatile关键字作用:

  1. 保证此变量对所有线程的可见性(即一个线程修改了这个变量的值,新值对于其他线程来说可以立刻得知)。普通变量的值在线程间传递需要通过主内存完成。
  2. 禁止指令重排序优化,普通变量仅仅会保证在该方法执行过程中所有依赖赋值结果的地方都能获取到正确的结果,不能保证变量赋值的操作顺序与代码中一致

JMM对Volatile变量定义的特殊规则:
假定:T线程V和W分别为两个Volatile变量,对其进行read load use assign store和Write需满足以下规则。

  1. 在线程T对V执行use时候前一个工作必须是load;并且只有当线程T对变量执行的最后一个动作是use的时候,才能对变量V执行load。线程T可以对变量V的use可以认为是线程T对变量load和read动作相关联,必须一起出现。
  2. 只有线程T对V执行的最后一个工作是assign的时候,线程T才能对V执行store动作;并且T对V执行的最后一个动作是store的时候,T才能对V执行assign的动作。T对V的assign动作可以看做T对V的store,write动作相关联,必须连续一起出现。
    3.要求Volatile修饰的变量不会被指令重排序优化,保证代码执行顺序与程序的顺序相同

原子性、可见性和有序性

原子性:基本数据类型的访问读写具备原子性

可见性:当一个线程修改了共享变量值,其他线程能够立即得知这个修改。除了Volatile外,java还有两个关键字能够实现可见性,synchronized和final。同步块的可见性是由对一个变量执行unlock操作前,必须先把此变量同步到主存中。final关键字的可见性是指:被final修饰的字段在构造器中一旦初始化完成,并且构造器没有吧this的引用传递出去,那么其他线程中就有可能看到final的值。

有序性:java提供Volatile和synchronized两个关键字来保证线程操作的原子性,Volatile本来就包含禁止指令重排序的寓意,synchronized则是由一个变量在同一个时刻只允许一个线程对其lock操作这条规则获得的,这条规则决定了持有同一个锁的两个同步快只能串行进入。

先行发生原则

先行发生原则指的是java内存模型中定义的两项操作之间的关系,例如操作A先行发生于操作B,操作A的影响能被B看到,影响包括了内存中共享变量的值,发送了消息,调用了方法等。

点赞(0)
版权归原创作者所有,任何形式转载请联系作者; Java 技术驿站 >> 高效并发 第一节:java内存模型(JVM笔记)

相关推荐