浅谈一下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 集成 Quartz并使用Cron 表达式实现定时任务

    Spring Boot 集成 Quartz并使用Cron 表达式实现定时任务

    本篇文章介绍了如何在 Spring Boot 中集成 Quartz 进行定时任务调度,并通过 Cron 表达式 控制任务执行时间,Quartz 提供了更强大的任务调度能力,比 @Scheduled 注解更灵活,适用于复杂的定时任务需求
    2025-04-04
  • 如何只返回实体类中的部分字段问题

    如何只返回实体类中的部分字段问题

    这篇文章主要介绍了如何只返回实体类中的部分字段问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-05-05
  • SpringBoot数据访问的实现

    SpringBoot数据访问的实现

    本文主要介绍了SpringBoot数据访问的实现,引入各种xxxTemplate,xxxRepository来简化我们对数据访问层的操作,感兴趣的可以了解一下
    2023-11-11
  • druid多数据源配置+Datasurce动态切换方式

    druid多数据源配置+Datasurce动态切换方式

    这篇文章主要介绍了druid多数据源配置+Datasurce动态切换方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • springboot使用jasypt加密库实现数据库加解密示例代码

    springboot使用jasypt加密库实现数据库加解密示例代码

    这篇文章主要给大家介绍了关于springboot使用jasypt加密库实现数据库加解密的相关资料,Jasypt是一个用于配置文件加密的Java库,它可以用来加密和解密配置文件中的敏感信息,如数据库密码、API 密钥等,需要的朋友可以参考下
    2024-04-04
  • java获取反射机制的3种方法总结

    java获取反射机制的3种方法总结

    这篇文章主要给大家介绍了关于java获取反射机制的3种方法,文中通过示例代码介绍的非常详细,对大家学习或者使用java具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-06-06
  • Java的字符读写类CharArrayReader和CharArrayWriter使用示例

    Java的字符读写类CharArrayReader和CharArrayWriter使用示例

    这篇文章主要介绍了Java的字符读写类CharArrayReader和CharArrayWriter使用示例,两个类分别继承于Reader和Writer,需要的朋友可以参考下
    2016-06-06
  • java实现Api接口加密通信方式

    java实现Api接口加密通信方式

    这篇文章主要介绍了java实现Api接口加密通信方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-06-06
  • Java通过反射,如何动态修改注解的某个属性值

    Java通过反射,如何动态修改注解的某个属性值

    这篇文章主要介绍了Java通过反射,动态修改注解的某个属性值操作,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • Mybatis CURD及模糊查询功能的实现

    Mybatis CURD及模糊查询功能的实现

    这篇文章主要介绍了Mybatis CURD及模糊查询功能的实现,有查询删除,插入,更新功能,通过实例代码讲解的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-06-06

最新评论