Java并发内存模型详情

 更新时间:2021年10月22日 08:44:37   作者:onlythinking  
这篇文章主要介绍了Java并发内存模型,Java是一门支持多线程执行的语言,要编写正确的并发程序,了解Java内存模型是重要前提。而了解硬件内存模型有助于理解程序的执行,下面文章就来看看详细内容吧

Java是一门支持多线程执行的语言,要编写正确的并发程序,了解Java内存模型是重要前提。而了解硬件内存模型有助于理解程序的执行。

本文主要整理以下内容

  • Java内存模型
  • 硬件内存架构
  • 共享对象可见性
  • 竞争条件

1、Java内存模型

Java内存模型最新修订是在Java5JSR-176 罗列了 J2SE5.0 相关发布特性,包含其中的 JSR-133(JavaTM内存模型与线程规范),java虚拟机遵循此规范。延续至今该内存模型在Java8中依然奏效。

JSR 全称 Java Specification Requests,意为Java标准化技术规范的正式请求。

Java程序运行在虚拟机上(Jvm)。从逻辑角度看,Jvm内存被划分为线程堆栈和堆。每个线程都拥有自己的堆栈,该线程堆栈存储的数据不对其它线程可见。堆内存用于存储共享数据。

线程堆栈存储方法中所有局部变量,包含原始类型(booleanbyteshortcharintlongfloatdouble)和对象引用。

堆存储需要共享对象和静态变量。

注意:对象不一定都会存储到堆内存。看下面例子,假如果Object对象不需要被其它线程共享,编译器会执行堆分配转化为栈分配。

解释一下,编译器会根据对象是否逃逸做出优化。优化的其中一项就是堆分配转化为栈分配,目的在于减轻GC压力,提升性能。此优化动作由Jvm参数-XX:+DoEscapeAnalysi 进行控制。Java8 默认开启。

测试:通过开启或关闭 -XX:+PrintGC -XX:-DoEscapeAnalysis 观察是否执行GC来判断对象存储位置。

public static void main(String[] args){
     for(int i = 0; i < 10000000; i++){
         createObj();
     }
 }
 public static void createObj(){
     new Object();
 }


2、硬件内存架构

如下图,现代计算机通常都装有2个或者更多的CPUCPU又可以是多核。一个CPU包含一组寄存器,每个CPU具有一个高速缓存,而高速缓存又分为L1,L2,L3,L4 不同层级缓存。

RAM为主存储也就是我们说的计算机内存,所有CPU都可以读取主存储。

CPU读取主存储数据时,它会将部分主存储数据读入CPU高速缓存中,又将缓存的中一部分读入寄存器执行,操作结束后,将值从寄存器刷新到高速缓存中,高速缓存在特定的时刻将数据统一刷新到内存中。

3、实际执行

事实上,上面阐述的Java堆栈内存模型是为了理解抽象出来的。实际执行就像下图一样,线程栈和堆的数据可能分散到硬件不同的存储区域。数据分散在不同区域会带来以下两个主要问题。

3.1 共享对象可见性

下面场景两个线程同时操作对象obj.count,其中一个线程对obj.count进行更新,但是对其它线程不可见。

线程A操作obj时,先从主存里拷贝一个数据副本到CPU高速缓存,又到寄存器,然后修改obj.count=2后刷新到CPU高速缓存,但是数据暂未同步到主存。以此同时线程B也操作obj,拷贝的数据副本仍然为obj.count=1,这会导致程序结果错误。

解决此问题,可以使用Java volatile关键字。volatile可简单理解为跳过CPU高速缓存,让修改结果及时同步到主存,从而保证了其它线程读到最新值。volatile 后期专门介绍。

3.2 竞争条件

另外一种情况假如果多个线程同时更行obj.count,这时会发生竞争条件。

解决方法,使用Java synchronized 保证线程执行顺序,另外synchronized包裹中的所有变量都直接从主存读取(跳过CPU高速缓存),并且当线程退出synchronized后,所有更新的变量将同步到主存。

总结:

本文记录Java内存模型,其中主要内容来源于 Jakob Jenkov 大神博客。

   http://tutorials.jenkov.com/java-concurrency/java-memory-model.html

到此这篇关于Java并发内存模型详情的文章就介绍到这了,更多相关Java并发内存模型内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot整合Thymeleaf小项目及详细流程

    SpringBoot整合Thymeleaf小项目及详细流程

    这篇文章主要介绍了SpringBoot整合Thymeleaf小项目,本项目使用SpringBoot开发,jdbc5.1.48,主要涉及到Mybatis的使用,Thymeleaf的使用,用户密码加密,验证码的设计,图片的文件上传(本文件上传到本地,没有传到数据库)登录过滤,需要的朋友可以参考下
    2022-03-03
  • Java反射机制的适用场景及利弊详解

    Java反射机制的适用场景及利弊详解

    这篇文章主要介绍了Java反射机制的适用场景及利弊详解,Spring用到很多反射机制,在xml文件或者properties里面写好了配置,然后在Java类里面解析xml或properties里面的内容,得到一个字符串,然后用反射机制,需要的朋友可以参考下
    2023-08-08
  • Spring中byName和byType的区别及说明

    Spring中byName和byType的区别及说明

    这篇文章主要介绍了Spring中byName和byType的区别及说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-12-12
  • 详解poi+springmvc+springjdbc导入导出excel实例

    详解poi+springmvc+springjdbc导入导出excel实例

    本篇文章主要介绍了poi+springmvc+springjdbc导入导出excel实例,非常具有实用价值,需要的朋友可以参考下。
    2017-01-01
  • SpringCloud中的Ribbon负载均衡详细解读

    SpringCloud中的Ribbon负载均衡详细解读

    这篇文章主要介绍了SpringCloud中的Ribbon负载均衡详细解读,当系统面临大量的用户访问,负载过高的时候,通常会增加服务器数量来进行横向扩展(集群),多个服务器的负载需要均衡,以免出现服务器负载不均衡,部分服务器负载较大,部分服务器负载较小的情况,需要的朋友可以参考下
    2023-11-11
  • Java Array与ArrayList区别详解

    Java Array与ArrayList区别详解

    这篇文章主要介绍了Java Array与ArrayList区别详解的相关资料,需要的朋友可以参考下
    2017-01-01
  • SpringBoot多数据源的两种实现方式实例

    SpringBoot多数据源的两种实现方式实例

    最近在项目开发中,需要为一个使用MySQL数据库的SpringBoot项目,新添加一个PLSQL数据库数据源,下面这篇文章主要给大家介绍了关于SpringBoot多数据源的两种实现方式,需要的朋友可以参考下
    2022-04-04
  • Java中的函数式编程

    Java中的函数式编程

    这篇文章介绍Java中的函数式编程,函数式编程是一种编程范式,其中程序是通过应用和组合函数来构造的。它是一种声明式编程范式,其中函数定义是表达式树,每个表达式树返回一个值,而不是一系列改变程序状态的命令语句,具体情况请看下文,希望对你有所帮助
    2021-10-10
  • C++内存管理看这一篇就够了

    C++内存管理看这一篇就够了

    这篇文章主要介绍了C/C++中的内存管理小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-08-08
  • lambda表达式解决java后台分组排序过程解析

    lambda表达式解决java后台分组排序过程解析

    这篇文章主要介绍了lambda表达式解决java后台分组排序过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-10-10

最新评论