JMM大致描述:

JMM描述了线程如何与内存进行交互。Java虚拟机规范视图定义一种Java内存模型,来屏蔽掉各种操作系统内存访问的差异,以实现Java程序在各种平台下都能达到一致的访问效果。

JMM描述了JVM如何与计算机的内存进行交互

JMM都是围绕着原子性,有序性和可见性进行展开的

JMM的主要目标是定义程序中各个变量的访问规则,虚拟机将变量存储到内存和从内存取出变量这样的底层细节。此处的变量指在堆中存储的元素。

多线程的时候为什么容易出错?

Java内存模型规定所有的共享变量都存储在主内存中,而每条线程有自己的工作内存(本地内存),工作内存保存了共享变量的副本,而不同内存又无法访问对方的工作内存,所以如果线程在工作内存中修改了变量副本,其它线程是无从得知的。

线程的传值均需要通过主内存来完成

主内存与工作内存如何交互?

Java内存模型定义了8种操作来完成主内存与工作内存的交互细节,虚拟机必须保证这8种操作的每一个操作都是原子的,不可再分的。

lock: 作用于主内存的变量,把变量标识为线程独占的状态

unlock: 与lock对应,把主内存中处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定。

read: 作用于主内存的变量,把一个变量的值从主内存传输到线程的工作内存,便于随后的load使用。

load:作用于工作内存的变量,把read读取到的变量放入工作内存副本

use: 作用于工作内存,把工作内存的变量值传递给执行引擎,每当虚拟机遇到一个需要使用到变量的值的字节码指令时将会执行这个操作。

assign: 作用于工作内存,把执行引擎收到的值赋给工作内存的变量,虚拟机遇到赋值字节码时候执行这个操作

store:作用于工作内存,把变量的值传输到住内存中,以便随后的write使用

write:作用于主内存,把store操作从工作内存得到的值放入主内存的变量中。

JMM内存模型

执行上述8种基本操作的规则:

不允许read和load,store和write操作之一单独出现。

不允许一个线程丢弃它最近的assign操作。即变量在工作内存中改变了账号必须把变化同步回主内存

一个新的变量只允许在主内存中诞生,不允许工作内存直接使用未初始化的变量。

一个变量同一时刻只允许一条线程进行lock操作,但同一线程可以lock多次,lock多次之后必须执行同样次数的unlock操作

如果对一个变量进行lock操作,那么将会清空工作内存中此变量的值。

不允许对未lock的变量进行unlock操作,也不允许unlock一个被其它线程lock的变量

如果一个变量执行unlock操作,必须先把次变了同步回主内存中。

这8种操作定义相当严禁,实践起来又比较麻烦,但是可以有助于我们理解多线程的工作原理。有一个与此8种操作相等的Happen-before原则。

Happen-before原则

这个是Java内存模型下无需任何同步器协助就已经存在,可以直接在编码中使用。如果两个操作之间的关系不在此列,并且无法从下列规则推导出来的话,它们的顺序就没有保障,虚拟机可以对他们进行任意的重排。

天然的happen-before

程序顺序原则:一个线程内包装语义的串行性

volatile变量的写,先发生于读,这保证了volatile变量的可见性

锁规则:unlock先与lock

传递性:A 先于B,B先于C,那么A必然先于C

线程的start先于线程的每一个动作

线程的所有操作优先于线程的终结(Thread.join())

线程的中断(interupt)先于被中断线程的代码

对象的构造函数执行,先于finalize()方法

Java运行时数据区

JVM定义了一些程序运行时会使用到的运行时数据区,其中一些会随着虚拟机启动而创建,随着虚拟机退出而销毁。另外一些是与现场一一对应的,这些线程对应的数据区会随着线程的开始和结束而创建和销毁。

这部分参考JVM规范

1. pc寄存器

可以支持多条线程同时允许,每一条Java虚拟机线程都有自己的pc寄存器。任意时刻,一条JVM线程之后执行一个方法的代码,这个方法被称为当前方法(current method)

如果这个方法不是native的,那么PC寄存器就保存JVM正在执行的字节码指令地址。

如果是native的,那么pc寄存器的值为undefined

pc寄存器的容量至少能保证一个returnAddress类型的数据或者一个平台无关的本地指针的值。

2. JVM Stack(虚拟机栈)

每一个JVM线程都有自己的私有虚拟机栈,这个栈与线程同时创建,用于存储栈帧(Frame)。

栈用来存储局部变量与一些过程结果的地方。在方法调用和返回中也扮演了很重要的角色。

栈可以试固定分配的也可以动态调整

如果请求线程分配的容量超过JVM栈允许的最大容量,抛出StackOverflowError异常

如果JVM栈可以动态扩展,扩展的动作也已经尝试过,但是没有申请到足够的内存,则抛出OutofMemoryError异常

3. Heap(堆)

堆是可以可供各个线程共享的运行时存储区域,也是供所有类的实例和数组对象分配内存的区域。堆在JVM启动的时候创建。

堆所存储的就是被GC所管理的各种对象。

堆也是可以固定大小和动态调整的:

实际所需的堆超过的GC所提供的最大容量,那么JVM抛出OutofMemoryError异常。

4. Method Area(方法区)

也是各个线程共享的运行时内存区,它存储每一个类的实例信息,运行时常量池,字段和方法数据,构造函数和普通方法的字节码等内容。还有一些特殊方法。

方法区是堆的逻辑组成部分,也在JVM启动时创建,简单的JVM可以不实现这个区域的垃圾收集。

方法区也可固定大小和动态分配与堆一样,内存空间不够,那么JVM抛出OutofMemoryError异常。

5. Run-Time Constant Pool(运行时常量池)

在方法区中分配,在加载类和接口到虚拟机之后,就创建对应的运行时常量池。

它是class文件中每一个类或接口的常量池表的运行时表现形式。像字符串。Java的主要类型。

存储区域不够用时候抛出OutofMemoryError异常。

6. Native Method Stacks(原生方法栈或本地方法栈)

JDK中native的方法,System类和Thread类中有很多。使用C语言编写的方法,这个也通常叫做C stack。

可以不支持本地方法栈,但是如果支持的时候,这个栈一般会在线程创建的时候按线程分配。

与栈的错误一样,StackOverFlowError和OutOfMemeoryError.

为了让学习变得轻松、高效,今天给大家免费分享一套Java入门教学资源。帮助大家在成为Java架构师的道路上披荆斩棘。需要入门的资料欢迎加入学习交流群:9285,05736

Java的多线程以及内存模型的知识点梳理,有想到过这些吗?相关推荐

  1. java线程内存模型_深度解析Java多线程的内存模型

    内部java内存模型 硬件层面的内存模型 Java内存模型和硬件内存模型的联系 共享对象的可见性 资源竞速 Java内存模型很好的说明了JVM是如何在内存里工作的,JVM可以理解为java执行的一个操 ...

  2. Java 并发编程解析 | 如何正确理解Java领域中的内存模型,主要是解决了什么问题?

    写在开头 这些年,随着CPU.内存.I/O 设备都在不断迭代,不断朝着更快的方向努力.在这个快速发展的过程中,有一个核心矛盾一直存在,就是这三者的速度差异.CPU 和内存的速度差异可以形象地描述为:C ...

  3. 深入理解Java虚拟机:jvm内存模型jdk1.8

    深入理解Java虚拟机:jvm内存模型jdk1.8 一.程序计数器 使用PC寄存器存储字节码指令地址有什么作用?为什么使PC寄存器记录当前线程的执行地址? PC寄存器为什么会被设定为线程私有? 二.J ...

  4. Java 并发编程解析 , 如何正确理解Java领域中的内存模型

    这些年,随着CPU.内存.I/O 设备都在不断迭代,不断朝着更快的方向努力.在这个快速发展的过程中,有一个核心矛盾一直存在,就是这三者的速度差异.CPU 和内存的速度差异可以形象地描述为:CPU 是天 ...

  5. Java虚拟机学习 - 体系结构 内存模型(转载)

    一:Java技术体系模块图 二:JVM内存区域模型 1.方法区 也称"永久代" ."非堆",  它用于存储虚拟机加载的类信息.常量.静态变量.是各个线程共享的内 ...

  6. Java Jvm虚拟机的内存模型概述 《对Java的分析总结》(一)

    <对Java的分析总结>-Java虚拟机的内存模型 ** 你可能需要 CSDN 网易云课堂教程 掘金 EDU学院教程 知乎 Flutter系列文章 头条同步 百度同步 本文章首发于微信公众 ...

  7. Java虚拟机学习 - 体系结构 内存模型

    一:Java技术体系模块图 二:JVM内存区域模型 1.方法区 也称"永久代" ."非堆", 它用于存储虚拟机加载的类信息.常量.静态变量.是各个线程共享的内存 ...

  8. Java虚拟机中的内存模型?JSP常用的动作标签及作用? 如何防止表单重复提交问题? JSP四大作用域及请求范围? 分别说出http,https,ftp,talnet的默认端口?

    文章目录 一 ,Java虚拟机中的内存模型JVM? 1,Java堆 2,方法区 3,Java栈 4,本地方法栈 问题扩展: 二 , JSP常用的动作标签及作用 (1)问题分析: (2)核心答案讲解: ...

  9. Java多线程_1_Java内存模型_内存模型的3大特性

    Java内存模型: 内存分布情况及其关系: 主内存:Java内存模型规定所有的变量都保存在主内存中 工作内存:每个线程都有自己的工作内存,保存了该线程使用到的变量的主内存副本拷贝 主内存与工作内存的关 ...

最新文章

  1. android逆向分析概述_Android存储概述
  2. vue 中使用promise
  3. C#—使用InstallerProjects打包桌面应用程序
  4. php 浏览商品记录,php浏览历史记录
  5. python数据库密码如何加密_MySQL怎么设置密码
  6. 华为云服务器配置ipv6,华为云获“IPv6支持度优秀奖”,持续助推云网融合
  7. hihoCoder #1449 : 后缀自动机三·重复旋律6
  8. Linux进制查看工具:od、hexdump、xxd
  9. 互联网晚报 | 4月11日 星期一 | 苏州放宽住房限售;苹果确认开始在印度生产iPhone 13;民航局将上报民航专项检查方案...
  10. 3-2:常见任务和主要工具之存储介质
  11. jquery 特效专辑
  12. oracle学习小结3之索引
  13. bmp转换tiff c++代码_如何快速转换图片格式
  14. 微信小程序背景音乐官方实例代码无效问题解决及音乐src获取方法
  15. javaWeb企业分布式、互联网、云开发平台-Jeesz
  16. 排序算法之十 希尔排序(C++版本)
  17. kafka日志清理策略
  18. 计算机属性设备管理器无图标,设备管理器图标的修改方法
  19. java怎么查看jar包_怎么查看Jar包源码?如何打开Jar文件?
  20. String类的常用方法都有哪些?

热门文章

  1. JavaScript,等比例缩放图片的函数,很好用。
  2. Unity-基本函数用法
  3. 检测oracle的语句,oracle功能检测sql语句
  4. c#调用c++的dll接口
  5. 设置窗口置顶_这三个应用,每一个都能让你置顶。
  6. linux 测试cpu计算圆周率_Linux下测试CPU性能
  7. pytorch的F.cross_entropy交叉熵函数
  8. PyTorch框架学习二十——模型微调(Finetune)
  9. 通过SVD求解单应矩阵
  10. SQL Server查询中特殊字符的处理方法