Loading

JVM内存模型

JVM内存模型(JAVA Memory Model,简称 JMM)

JMM:用于定义变量(所有线程的共享变量,不能是局部变量)的访问规则。

JMM将内存划分为两个区:主内存区和工作内存区

  • 主内存区:真实存放变量
  • 工作内存:主内存中变量的副本,供各个线程使用

注意

  • 各个线程 只能访问自己私有的工作内存(不能访问其他线程的内存,也不能访问主内存)
  • 不同线程之间可以通过主内存间接的访问其他线程的工作内存。

各个线程只能访问自己的工作内存,那么A线程如何获取B线程的值?

  1. 将线程B的数据同步到主内存(Save:将工作内存的数据刷到主内存)
  2. 线程A获取主内存中的最新数据(Load:主内存到工作内存)

不同线程之间数据如何交互

刚才介绍了 Save 和 Load 两个动作,但是不同线程之间数据交互的步骤不仅仅只有这两个,下面我们完整介绍一下交互步骤。

  1. Lock : 将主内存中的数据,标识为一条线程的独占状态。
  2. Read : 将主内存中的变量,读取到工作内存中。
  3. Load:将上一步读取的变量,拷贝到变量副本当中。
  4. Use:将工作内存中的变量副本,传递给线程去使用。
  5. Assign:将线程正在使用的变量,传递给工作内存中的变量副本。
  6. Store:将工作内存中变量副本的值,传递到主内存中。
  7. Write:将变量副本作为主内存中的变量进行储存。
  8. UnLock:解除线程的独占状态。

JVM要求以上的八个动作必须是原子性的。

但是JVM对于64位的数据类型(long/double)有非原子性协议!!long和double占用的字节数都是8,也就是64bits。在32位操作系统上对64位的数据的读写要分两步完成,每一步取32位数据。这样对double和long的赋值操作就会有问题:如果有两个线程同时写一个变量内存,一个进程写低32位,而另一个写高32位,这样将导致获取的64位数据是失效的数据。因此需要使用volatile关键字来防止此类现象。volatile本身不保证获取和设置操作的原子性,仅仅保持修改的可见性。但是java的内存模型保证声明为volatile的long和double变量的get和set操作是原子的。

If you’re going to reuse code, you need to understand that code!
posted @ 2020-12-20 21:25  不颓废青年  阅读(165)  评论(0编辑  收藏  举报