【JVM】内存模型与优化并发操作

JMM与内存交互

Java内存模型的主要目的是定义程序中各种变量的访问规则。Java内存模型的意义,在不同的平台上实现读写的一致性。尤其是对于并发问题。主内存与工作内存的交互。 主内存主要对应于Java堆中的对象实例数据部分,而工作内存则对应于虚拟机栈中的部分区域。

  • Java内存模型规定了:
  1. 所有的变量都存储在主内存中。包括了实例字段、静态字段和构成数组对象的元素,但是不包括局部变量与方法参数,因为后者是线程私有的。
  2. 每条线程还有自己的工作内存,线程的工作内存中保存了被该线程使用的变量的主内存副本
  3. 线程对变量的所有操作(读取、赋值等)都必须在工作内存中进行,而不能直接读写主内存中的数据。
  4. 不同的线程之间也无法直接访问对方工作内存中的变量,线程间变量值的传递均需要通过主内存来完成。
    【JVM】内存模型与优化并发操作

内存交互

JVM在实现时能够对一些操作保证原子性(8种):lock, unlock, read, use, load, assign, store, write.

很多操作具有成对性质且保证顺序,但是不必连续执行。线程不许丢弃最近的assign的操作,同样不许一个变量没有被assign就被传回。一个变量只能从主内存中诞生。对一个变量lock时,会清空工作内存中此内存的值,在unlock之前,需要把变量刷回主内存。

可见性、重排序、原子性

volatile关键字,这部分内容可以见并发内容的复习。

8条happens-before:

  1. 程序串行先后,本线程内操作有序。
  2. 锁先后
  3. 线程启动先后
  4. volatile规则
  5. 线程终止先后
  6. 线程中断先后
  7. 对象终结先后
  8. 传递性先后

线程安全

  • 不可变时线程安全的
  • 互斥同步时安全的,synchronized和reentrantlock
  • 非互斥同步,乐观锁的方法。有冲突就回退。

锁优化

自旋锁与自适应自旋

  • 自旋:如果线程可以很快获得锁,那么可以不挂起线程,而是让线程进行几个忙循环。节省线程挂起和切换的时间。
  • 自适应自旋:自旋时间不再固定,而是由前一个在同一个锁的自旋时间和当前锁的状态绝对。

锁消除

  • 在编译代码时候,检测到不存在数据竞争,JVM会锁消除。-XX:+EliminteLocks开启,并且需要逃逸分析-XX:+DoEscapeAnalisis

  • 逃逸分析:方法中定义的对象可能别外部方法引用,称为方法逃逸;如果对象可能被外部线程访问,称为线程逃逸。如赋值给类变量或者可以在其他线程中仿真的实例变量。

锁粗化,轻量化锁,偏向锁

锁粗化:建议加到锁的同步范围扩大。合并多个synchronized

轻量化锁:优先使用乐观锁,如果失败升级为重量级锁。

偏向锁:在无竞争时,直接取消了锁。

【JVM】内存模型与优化并发操作