浅谈一下Java中的内存模型JMM

 更新时间:2023年08月11日 09:00:53   作者:刘婉晴  
这篇文章主要介绍了浅谈一下Java中的内存模型JMM,JMM,全程是 Java Memory Model ,直译就是 Java 内存模型,根据这个名字,可以知道它是 Java 设计用来管理内存的一个模型,需要的朋友可以参考下

一、什么是 JMM

JMM,全程是 Java Memory Model ,直译就是 Java 内存模型。根据这个名字,可以知道它是 Java 设计用来管理内存的一个模型。

Java 中的内存分为主内存和本地内存,线程之间的共享变量存储在主内存(Main Memory)中,每个线程都有一个私有的本地内存(Local Memory),本地内存中存储了该线程以读/写共享变量的副本。下图很清晰地阐述了这个关系 :

请添加图片描述

因为 Java 通过共享内存作为线程间的通信机制,因此 JMM 和线程通信息息相关,可以说 JMM 控制线程的通信,具体来说 JMM 控制一个线程对共享变量的写入何时对另一个线程可见 。

二、 JMM 基础

本节介绍了解 JMM 需要的一些前置知识, 即和 JMM 有关的一些概念

2.1 Java 线程通信机制

线程通信机制一共有两种(共享内存 和 消息传递), Java 使用 共享内存模型 作为线程同步机制

2.2 同步

同步是指程序如何控制不同线程操作发生的相对顺序,在多线程并发情况下,同步是保证多线程下安全问题的非常重要的操作。

2.3 堆内存

Java 内存有栈内存、堆内存 和 方法区 。 堆内存中含有线程共享的 实例、静态变量 和 数组元素等 ,也就是说堆内存是线程共享区 。

2.4 指令重排

正常情况,按照我们的理解,我们写一段程序在处理器中就是按照我们写的顺序执行的 。

但是实际上,在我们看不到的地方,处理器为了提高执行效率,优化性能,会对指令进行重排 。

以下面的程序为例子,解释指令重排:

int a = 1;  // ....  语句1
int b = 2; // ..... 语句 2

正常情况下, 语句 1 优先于 语句 2 执行 。

但是,处理器实际在执行时,会根据情况进行处理,可能会出现 语句2 优先与 语句1 执行的情况。

但是因为对程序的执行结果没有影响, 所以,我们程序员不知道发生了指令重排 。

在单线程情况下,指令重排不影响程序运行的结果。但是多线程情况下,可能会造成影响。

因此, JMM 通过插入 内存屏障 禁止特定类型的处理器重排序来保证多线程并发下的程序执行安全 。

2.5 顺序一致性模型

顺序一致性模型,是 JMM 为保证多线程下的安全而提出的,正确同步的程序应该具有顺序一致性,其具有如下特点:

按照程序顺序执行,不能重排序操作原子执行,对所有线程可见 2.6 同步程序

同步程序并不是完全按照顺序一致性执行,其在临界区内可以进行重排序,这样的设计给了处理器足够的优化空间,同时也没有改变程序的执行结果 。

三、volatile 关键字

3.1 volatile 做什么

volatile 相当于同一个锁对对该变量的读写操作进行了同步,用 volatile 修饰的变量总是能被同步到共享内存中,避免了因为本地内存的存在导致的线程不安全问题 。volatile 具有如下两个特性:

  • 可见性:一个线程的读,总是能看到另一个线程的写
  • 原子性: 对单个变量的读写具有原子性, 但是对复合操作不具有原子性

3.2 volatile 原理

3.2.1 规则

  • 当第二个操作是volatile写时,不管第一个操作是什么,都不能重排序
  • 当第一个操作是volatile读时,不管第二个操作是什么,都不能重排序
  • 当第一个操作是volatile写,第二个操作是volatile读时,不能重排序

3.2.2 实现

生成字节码时,会在指令序列中插入内存屏障来禁止特定类型的处理器重排序

四、锁的内存语义

  • 锁释放与volatile写有相同的内存语义
  • 锁获取与volatile读有相同的内存语义

4.1 AQS Java同步器框架

AQS使用一个整型的volatile变量来维护同步状态, 实现 ReentrantLock

4.2 concurrent包

concurrent 包依赖于 CAS 和 volatile 实现

  • 声明共享变量为volatile
  • 使用CAS的原子条件更新来实现线程之间的同步
  • 配合以 volatile 的读/写和 CAS 所具有的 volatile 读和写的内存语义来实现线程之间的通信

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

相关文章

  • 聊聊spring boot的WebFluxTagsProvider的使用

    聊聊spring boot的WebFluxTagsProvider的使用

    这篇文章主要介绍了聊聊spring boot的WebFluxTagsProvider的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-07-07
  • IDEA进程已结束,退出代码-1073741819 (0xC0000005)的bug

    IDEA进程已结束,退出代码-1073741819 (0xC0000005)的bug

    这篇文章主要介绍了IDEA进程已结束,退出代码-1073741819 (0xC0000005)的bug,本文通过实例代码图文的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-04-04
  • java实现手机短信验证的基本思路

    java实现手机短信验证的基本思路

    这篇文章主要为大家详细介绍了java实现手机短信验证的基本思路,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-11-11
  • 浅谈为什么同一个java文件只能有一个public类

    浅谈为什么同一个java文件只能有一个public类

    这篇文章主要介绍了浅谈为什么同一个java文件只能有一个public类,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-11-11
  • Spring Cloud Data Flow初体验以Local模式运行

    Spring Cloud Data Flow初体验以Local模式运行

    这篇文章主要介绍了Spring Cloud Data Flow初体验以Local模式运行,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-08-08
  • Java实现广度优先遍历的示例详解

    Java实现广度优先遍历的示例详解

    广度优先遍历:广度优先遍历是连通图的一种遍历策略,因为它的思想是从一个顶点V0开始,辐射状地优先遍历其周围较广的区域故得名。本文详细介绍了Java如何实现广度优先遍历,感兴趣的小伙伴可以学习一下
    2022-02-02
  • Springboot创建子父工程过程图解

    Springboot创建子父工程过程图解

    这篇文章主要介绍了Springboot创建子父工程过程图解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-02-02
  • 使用IDEA向Gitee提交SpringBoot项目进行远程管理

    使用IDEA向Gitee提交SpringBoot项目进行远程管理

    本文主要介绍了使用IDEA向Gitee提交SpringBoot项目进行远程管理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-01-01
  • 深入理解Spring Boot属性配置文件

    深入理解Spring Boot属性配置文件

    这篇文章主要给大家深入的介绍了关于Spring Boot属性配置文件的相关资料,文中介绍的很详细,相信对大家具有一定的参考借鉴价值,需要的朋友们下面来一起看看吧。
    2017-02-02
  • 详解maven中profiles使用实现

    详解maven中profiles使用实现

    本文主要介绍了maven中profiles使用实现,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02

最新评论