概要

Java内存模型即Java Memory Model,简称JMM。

Java内存模型定义了多线程之间共享变量的可见性以及如何在需要的时候对共享变量进行同步。

线程包括:通信和同步。

  • 线程之间的通信:通信机制包括共享内存和消息传递;
  • 线程之间的同步:指程序用于控制不同线程之间操作发生相对顺序的机制;
  • Java的并发采用的是共享内存模型;

硬件内存架构

java如何写在单片机中 java mcu_开发语言

  • 在CPU内部有一组CPU寄存器,也就是CPU的储存器。
  • 在主存和CPU寄存器之间还存在一个CPU缓存,CPU操作CPU缓存的速度快于主存但慢于CPU寄存器。
  • 某些CPU可能有多个缓存层(一级缓存和二级缓存)。
  • 计算机的主存也称作RAM,所有的CPU都能够访问主存。
  • 系统有自己的缓存一致性协议。
  1. 当一个CPU需要访问主存时,会先读取一部分主存数据到CPU缓存,进而在读取CPU缓存到寄存器。
  2. 当CPU需要写数据到主存时,同样会先flush寄存器到CPU缓存,然后再在某些节点把缓存数据flush到主存。

Java内存模型

线程之间的共享变量存储在主内存(main memory)中,每个线程都有一个私有的本地内存(local memory),本地内存中存储了该线程以读/写共享变量的副本。

java如何写在单片机中 java mcu_java如何写在单片机中_02

Java内存模型把内存分成了:线程栈区和堆区;

java如何写在单片机中 java mcu_java_03

栈区
  • 每个线程都拥有自己的线程栈(调用栈),线程栈包含了当前线程执行的方法调用相关信息。
  • 线程栈包含当前方法的所有本地变量信息,本地变量对其它线程是不可见的。
堆区
  • 堆区包含了Java应用创建的所有对象信息,不管对象是哪个线程创建的。不管对象是属于一个成员变量还是方法中的本地变量,它都会被存储在堆区。
备注
  • 一个本地变量如果是原始类型,那么它会被完全存储到栈区。
  • 一个本地变量也有可能是一个对象的引用,这种情况下,这个本地引用会被存储到栈中,但是对象本身仍然存储在堆区。
  • 对于一个对象的成员方法,这些方法中包含本地变量,仍需要存储在栈区,即使它们所属的对象在堆区。
  • 对于一个对象的成员变量,不管它是原始类型还是包装类型,都会被存储到堆区。

Java内存模型和硬件架构

Java内存模型和硬件内存架构并不一致,导致出现以下问题:

  • 共享对象的可见性:CPU缓存在没有flush到主存的时候,可能会被其他Java线程拷贝到线程栈区中;
  • 使用volatile可以保证变量会直接从主存读取,而对变量的更新也会直接写到主存;
  • 竞争现象:线程共享对象同时被修改,产生竞争现象;
  • synchronized等机制解决抢占;