JVM 内存间的交互操作

JVM 内存间的交互操作

  • 背景
  • 操作指令
  • 规约及思考
  • 总结

Java的内存模型划分为主存和工作内存,那主存和工作内存如何协调呢?这些协调操作又有哪些呢?

背景

内存运行的速度已经够快了,但CPU寄存器、高速缓存却比其更快~为了充分利用这特性(资源),JVM规划了两块区域,工作内存和主存,其中工作内存对应CPU寄存器、高速缓存部分,主存即对应内存部分,而协调主存和工作内存上的相关的变量值则需要依靠一些指令进行。


操作指令

1. read 读取,作用于主内存的变量,从主存读取变量,为下一步的load操作做准备。
2. load 加载,只有在read之后,才能进行load的操作,作用于工作内存,将read读取的变量加载至工作内存。
3. use 使用, 作用于工作内存,当JVM遇到使用某个变量的值的字节码时执行此指令后,将变量值递交给执行引擎进行运算。
4. assign 分配(赋值),执行引擎接收到变量值后,执行分配操作,将变量赋值给工作内存的变量。
5. store 存储,在工作内存中,某个变量被修改之后,需要同步会主存时,执行此操作。
6. write 写入,真正执行将变量同步至主存的操作。
7. lock 加锁,作用于主内存,将某个变量标识为已有线程独占该变量的状态了。 8. unlock 解锁,将lock状态释放出来后,才能接着lock。


规约及思考

  1. 所有变量(指成员变量、静态变量等)诞生于主存中,工作内存保存的只是一个副本。这一点比较好理解,这些个变量属于线程共享的,而工作内存属于线程私有的,放在主存中也就无可非议了。
  2. 根据第一条规定。store操作之前必定有load,总不能说我没有从主存中读取某个变量,就无故往主存放变量吧,必须确保这些个变量来源于主存。use操作之前必先有assign操作,use操作将变量递交给执行引擎运算,那么这些个变量总得先assign一下吧。
  3. 最新的assign操作必定同步至主存。(如果最新的assign前后没有变化需要同步至主存吗?要是我设计的话肯定不给,但时间跟空间不可兼得,这意味着需开辟额外的空间保存最初的值。)
  4. 不予许read和load操作单一出现,不予许store和write操作单一出现。允许这两对指令之间插入其他指令。这意味,一个变量read之后,必被load进工作内存,store操作之后必被write进行主存,不存在主存或者工作内存单方面丑拒的状态。
  5. 上述讲的8种指令是原子操作的,对于64位的变量如double、long来说,read和load,store和write操作可以不是原子性的。这点也好理解,兼顾32位的操作系统。
  6. lock某个变量成功之后的线程会清除工作内存的该变量,确保能读到最新的值lock之前可能被修改过)。同个线程可以重复lock,但也需要执行相同次数的unlock(可重入的概念)。
  7. unlock操作之前,需要将变量同步会主存即store、write操作,这点很好理解,确保线程在加锁过程中的操作及时同步至主存。

总结

通过上述操作的协调进行,在并发场景下,我们有能力做到线程安全。比如synchronized操作,其本质就是lock住某个变量,然后再进行read、load等操作。再如volatile,为了保证其他线程的可见性,也是需要load和store的操作。那问题又来了,volatile的可见性就一定是立即可见的吗?synchronized了有为何还需要volatile?

你可能感兴趣的:(JVM深入学习,jvm,内存模型,内存交互)