Jvm

内存模型

释放双眼,带上耳机,听听看~!

在Java虚拟机中定义了一种内存模型也就是JMM。目的是屏蔽各种硬件和操作系统的内存差异,以解决Java跨平台时能达到统一的内存访问效果。下面我们了解一下在JMM中内存是怎么划分的。

JMM的目的就是为了解决程序中各个变量的访问规则,也就是虚拟机将变量存储到内存和从内存中读取变量的底层实现。但这里面所说的变量只包括实例变量和静态变量,并不包括局部变量。因为局部变量是线程私有的,并不会被其它线程所共享。所以不存在数据竞争的问题,所以在多线程执行时,局部变量是不会出线线程安全问题的。既然实例变量和静态变量是被所有线程共享的,那么在JMM中虚拟机是怎么保证在线程程执行时,变量的线程安全呢?

  • 主内存与工作内存

在JMM中有一个规定就是所有变量都必须存储在主内存中。主内存也就是虚拟机内存的一部分区域。除此之外,每一个线程都有自己独立的工作内存。线程工作内存与主内存的区别是?线程在执行时会把所需要的变量从主内存拷贝到工作内存中。线程对变量的所有操作包括读取、赋值等都必须在线程自己的工作内存中进行,而不能直接操作主内存中的变量。不同线程与线程间的是无法直接访问对方工作内存中的变量的。如果某一个线程需要访问其它线程工作内存中的变量时,它们只能通过主内存来完成。下图是线程与工作内存、主内存之间的关系图。

上述所说的主内存和工作内存与并不是我们常说的虚拟机中的堆、 栈、 方法区等。它们并不是一个内存概念。为了方便理解我们可以认为主内存就是虚拟机堆中的存储对象实例的内存,而工作内存就是虚拟机栈中的内存。

  • 内存间交互

下面我们来详细了解一下,一个变量是怎么从主内存拷贝到线程的工作内存中的。在JMM中主要定义了8种操作来完成上述的工作,并且这8种操作都是原子性的,不可分割的。它们分别是:

  • lock(锁定):目的是把主内存中的变量标识为线程已经锁定的状态。
  • unlock(解锁):目的是把主内存中已经是锁定状态的变量解锁,解锁后的变量可以被其他线程锁定。
  • read(读取):目的是把变量的值从主内存中传输到线程的工作内存中。
  • load(载入):目的是把主内存中得到的变量值存储到工作内存的变量副本中。
  • use(使用):目的是把工作内存中变量的值传递给执行引擎。
  • assign(赋值):目的是把执行引擎接收到的值赋给工作内存中的变量。
  • store(存储):目的是把工作内存中变量的值传送到主内存中。
  • write(写入):目的是把工作内存中得到的变量的值放入主内存的变量中。

上述就是每种操作的具体功能。按照上述的规则。如果要把变量从主内存复制到工作内存中那就要顺序地执行read和load操作,如果要把变量从工作内存同步回主内存时,就要顺序地执行store和write操作。 在虚拟机执行上述操作时有一些默认的规定,它们具体是。

  • 不允许一个变量从主内存读取了但工作内存不接受,或者从工作内存发起了同步但主内存不接受的情况。
  • 不允许变量在工作内存中改变了之后不同步到主内存中。
  • 不允许线程在没有发生任何改变的情况下把数据从线程的工作内存同步回主内存中。
  • 变量只能在主内存中产生,不允许在工作内存中直接使用一个未初始化的变量。
  • 变量在同一个时刻只允许一条线程对其进行lock操作。
  • 如果对变量执行lock操作时,线程会清空工作内存中此变量的值。
  • 如果变量事先没有被lock锁定,那不允许对它执行unlock操作,也不允许去unlock一个被其他线程锁定的变量。
  • 对变量执行unlock操作之前,必须先把此变量同步回主内存中。
0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧