铁锤的IT奇妙探险 Java Back-End Coder

Java内存模型-JMM

2020-07-16

JMM
   

介绍什么是Java内存模型,和JVM的区别和联系

JMM

JMM与JVM内存结构

  • JVM内存结构包括六个部分:堆,方法区(这两者是每个线程私有的),虚拟机栈(Java方法服务),本地方法栈(Native方法服务),程序计数器
  • JMM是和多线程相关的一组规范,保证不同JVM运行同一段代码的结果相同,JMM最重要的三点:重排序,原子性,内存可见性

指令重排

JVM和CPU有时为了优化处理速度,会对实际指令执行的顺序进行调整。如下所示:

重排分为三种情况:

  1. 编译器优化
  2. CPU重排
  3. 内存重排

原子性

Java中的原子操作:

  • 除了 longdouble 之外的基本类型(int、byte、boolean、short、char、float)的读/写操作,都天然的具备原子性;
  • 所有引用 reference 的读/写操作;
  • 加了 volatile 后,所有变量的读/写操作(包含 long 和 double);
  • JUC原子类中的一部分方法是具备原子性的,比如 AtomicInteger 的 incrementAndGet 方法。
  • long和double的读写非原子性操作是因为:它们占用64位的空间,可能被拆分成两个32位进行操作。不过现在主流JVM都会把64位数据的读写作为原子操作。

可见性

图中write()方法是将x赋值为1,read()为读取x,可以看出x初始值为0,对于线程1、2的工作内存而言,都可以从主内存中获取该值。然后线程1执行write()方法将x改成1,这个步骤发生在线程1的工作内存中,所以主内存x依旧为0,因此对于线程2察觉不到x的变化,这就是可见性问题。

主内存与工作内存

共享变量的可见性问题根本上是由CPU与内存之间的多级缓存层引起的。

  • 主内存放的是共享变量
  • 工作内存放的是共享变量的副本

关系

  1. 所有变量存储在主内存中,每个线程有独立的工作内存
  2. 线程不能直接读写主内存中的变量,可以操作自己的工作内存的变量,然后同步到主内存
  3. 线程间需要通信必须借助主内存中转

Similar Posts

上一篇 Future解析

Comments