Java并发内存模型详情

作者:onlythinking 时间:2023-06-04 23:50:23 

目录
  • 1、Java内存模型

  • 2、硬件内存架构

  • 3、实际执行

    • 3.1 共享对象可见性

    • 3.2 竞争条件

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

本文主要整理以下内容

  • Java内存模型

  • 硬件内存架构

  • 共享对象可见性

  • 竞争条件

1、Java内存模型

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

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

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

Java并发内存模型详情

线程堆栈存储方法中所有局部变量,包含原始类型(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();
}

Java并发内存模型详情

2、硬件内存架构

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

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

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

Java并发内存模型详情

3、实际执行

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

Java并发内存模型详情

3.1 共享对象可见性

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

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

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

Java并发内存模型详情

3.2 竞争条件

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

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

Java并发内存模型详情

总结:

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

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

来源:https://www.onlythinking.com/2020/06/08/java%E5%B9%B6%E5%8F%91%E4%B9%8B%E5%86%85%E5%AD%98%E6%A8%A1%E5%9E%8B/

标签:Java,并发,内存模型
0
投稿

猜你喜欢

  • MP(MyBatis-Plus)实现乐观锁更新功能的示例代码

    2022-10-27 15:41:24
  • Android Flutter实现3D动画效果示例详解

    2022-04-12 19:34:35
  • C#微信公众号开发之自定义菜单

    2023-01-23 02:07:08
  • Unity Shader实现裁切效果

    2023-03-05 07:54:24
  • android使用AsyncTask实现多线程下载实例

    2023-02-02 16:30:04
  • Android实用的代码片段 常用代码总结

    2022-02-02 20:29:53
  • C#实现餐厅管理系统

    2023-11-27 16:05:05
  • 如何使用Java给您的图片瘦身之Thumbnailator技术

    2023-10-31 10:25:52
  • JavaWeb开发中alias拦截器的使用方法

    2023-08-20 10:36:55
  • Hadoop的安装与环境搭建教程图解

    2022-06-28 16:19:47
  • maven将项目打包上传到nexus私服的详细教程

    2023-04-18 16:20:22
  • Java深入讲解异常处理try catch的使用

    2023-11-04 13:00:32
  • springboot整合Quartz实现动态配置定时任务的方法

    2023-03-08 22:13:10
  • Android中检查、监听电量和充电状态的方法

    2023-05-15 23:23:19
  • JWT在OpenFeign调用中进行令牌中继详解

    2023-02-07 04:19:15
  • Android RecyclerView实现水平、垂直方向分割线

    2023-07-24 15:40:35
  • SpringBoot+netty-socketio实现服务器端消息推送

    2023-11-15 06:14:31
  • feign GET请求不支持对象传参的坑及解决

    2023-07-29 18:10:25
  • Java 二分查找算法的实现

    2022-07-23 11:10:13
  • 浅谈java的接口和C++虚类的相同和不同之处

    2023-08-05 12:01:51
  • asp之家 软件编程 m.aspxhome.com