JMM和JVM内存模型

原作者博客: Java Memory Model

JVM内存模型

JVM内存模型中包括:

  • 程序计数器(PC)
  • java虚拟机栈
  • 本地方法栈
  • java堆
  • 方法区
程序计数器(PC)

程序计数器是一块很小的内存空间,用于记录下一条要运行的指令。每个线程都需要一个程序计数器,各个线程之中的计数器相互独立,是线程中私有的内存空间

java虚拟机栈

java虚拟机栈也是线程私有的内存空间,它和java线程同一时间创建,保存了局部变量、部分结果,并参与方法的调用和返回

本地方法栈

本地方法栈和java虚拟机栈的功能相似,java虚拟机栈用于管理Java函数的调用,而本地方法栈用于管理本地方法的调用,但不是由Java实现的,而是由C实现的

java堆

为所有创建的对象和数组分配内存空间,被JVM中所有的线程共享

方法区

也被称为永久区,与堆空间相似,被JVM中所有的线程共享。方法区主要保存的信息是类的元数据,方法区中最为重要的是类的类型信息、常量池、域信息、方法信息,其中运行时常量池就在方法区,对永久区的GC回收,一是GC对永久区常量池的回收;二是永久区对元数据的回收

JMM(java memory model) java内存模型

在多线程环境下,线程之间的要通信,就不得不提JMM(java内存模型)
在JVM内部使用的java内存模型(JMM)将线程堆栈和堆之间的内存分开
线程堆栈(thread stack):

1.运行在java虚拟机上的每个线程都有自己的线程堆栈(thread stack)

2.线程堆栈还包含正在执行的每个方法的所有局部变量,一个线程只能访问它自己的线程堆栈。由线程创建的局部变量对于除创建它的线程之外的所有其他线程都是不可见的。

3.即使两个线程正在执行完全相同的代码,两个线程仍然会在每个线程堆栈中创建该代码的局部变量,一个线程可能会将一个有限变量的副本传递给另一个线程,但它不能共享原始局部变量本身

堆:

1.堆包含在Java应用程序中创建的所有对象,而不管是不是由线程创建的该对象。

2.堆中的对象可以被具有对象引用的所有线程访问。当一个线程访问一个对象时,它也可以访问该对象的成员变量。

3.如果两个线程同时调用同一个对象上的一个方法,它们都可以访问该对象的成员变量,但每个线程都有自己的局部变量副本

4.堆中的数据是共享的,线程不安全的

共享对象的可见性

如果两个或多个线程共享一个对象,但没有正确使用volatile声明或Synchronized同步机制,一个线程更新了共享变量值后,对于其他线程来讲是不可见的。如线程A,线程B同时要进行modify,

public class Account {

  private float balance;

  public void modify (float difference) {
    float value=this.balance;
    this.balance=value+difference;
  }
}

首先,线程A和线程B在各自的thread stack中维护了一分局部变量的副本,线程A修改修改了线程A中Thread stack中的局部变量,但是还没有还没将修改的数据刷新到Main Memory中,而线程B获取的值依然是old value,就会出现问题

解决方案

  • 使用volatile关键字
  • 使用synchronized同步机制

这里写图片描述

图画的自己都不知道正不正确…

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐