Java多线程(四)

编程

 

Java源代码.java文件 --> 经过 Java编译器 --> Java字节码.class文件 --> 进入 JVM

-->  Class Loader类加载器 --> Runtime Data Area 运行时数据区 --> Execution Engine 执行引擎 

 

主要指的是 Runtime Data Area 运行时数据区 , 程序执行期间用到的数据和信息保存区

 

根据官方JVM.11文档 下图 , 运行时数据区有 程序计数器、JVM栈、堆、方法区、运行时常量池、本地方法栈等主要部分

 

程序计数器

  • 每一线程对应有一个程序计数器
  • 线程的程序计数器是线程私有的, 互不影响, 线程安全
  • 程序计数器记录线程正在执行的内存地址, 中断的线程恢复时可按当前内存地址追踪继续执行(CPU时间片资源切换)

 

JVM 栈 (Java栈、线程栈)

  • 每一个线程都有各自的一个栈
  • 每个栈由某干栈帧组成
  • 每个Java方法对应一个栈帧
  • 栈帧结构: 局部变量表(基本类型变量、引用类型对象的引用)、操作数栈、动态连接方法、返回地址等
  • 栈帧在方法运行时, 创建并入栈, 返回值就是该栈帧弹出的元素, 方法执行完该栈帧被清除
  • 栈顶的栈帧叫活动栈, 表示当前执行的方法, 才可以被CPU执行
  • 线程请求的栈深度大于虚拟机限定的深度, 将抛出StackOverflowError
  • 栈扩展时无法申请足够的内存, 就会抛出OutOfMemoryError

 

方法区

  • 方法区是Java堆的永久区
  • 方法区存放了要加载的类信息(名称、修饰符等), 类中的静态常量、类中定义为final类型的常量、字段信息、方法信息
  • 方法区是被Java线程共享的
  • 方法区要使用的内存超过其允许的大小时, 会抛出OutOfMemoryError: PremGen space/metaspace

 

常量池

  • 常量池是方法区的一部分
  • 常量池中存储两类数据: 字面量(字符串、final变量等)、引用量(类/接口、方法和字段的名称和修饰符)
  • 常量池在编译期间就被确定, 并保存在.class文件中

 

本地方法栈

  • 本地方法栈和栈相似, 区别是栈运行Java方法服务, 本地方法栈执行Native方法服务
  • 本地方法栈会抛出StackOverflowError 和 OutOfMemoryError
  • 用不到, 不做记录, 后续可以深究

 

  • java堆在虚拟机启动的时候建立,它是java程序最主要的内存工作区域
  • 几乎所有的java对象实例都存放在java堆中
  • 堆空间是所有线程共享的
  • 垃圾自动回收机制在这个区域

 

 

学习多线程 简单过一遍Java内存模型, 会发现多线程的线程安全问题主要发生在堆中, 多线程CPU执行读写操作共享数据不一致引起 

由此可以理解为什么多线程会要保证三个特性: 原子性、可见性、有序性

  • 原子性: 多个操作要么全部执行, 要么都不执行 (会发现和Java事务一样,保证数据安全的标准)
  • 可见性: 多个线程访问同一个变量时, 一个线程修改了变量的值, 其他线程能够立即看到该值, 比如多线程修改的对象在堆中, 还没等CPU执行修改写入时, 就被其他线程读取出去操作, 没见到就不安全了(单线程就没有可见性, 所以安全)
  • 有序性: 程序执行的顺序按代码的先后顺序希望执行, 多线程执行的顺序是不确定的, 不人为干涉就是随机执行了, 需要一些手段确保代码顺序执行

 

                                                                                                                                                今天太阳好大

以上是 Java多线程(四) 的全部内容, 来源链接: utcz.com/z/515324.html

回到顶部