浅谈一下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内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 详解maven安装教程以及解决安装不成功的解决办法

    详解maven安装教程以及解决安装不成功的解决办法

    这篇文章主要介绍了详解maven安装教程以及解决安装不成功的解决办法,详细的介绍了几种解决方法,非常具有实用价值,需要的朋友可以参考下
    2018-12-12
  • java springboot中如何读取配置文件的属性

    java springboot中如何读取配置文件的属性

    大家好,本篇文章主要讲的是java springboot中如何读取配置文件的属性,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
    2022-01-01
  • SpringBoot返回统一的JSON标准格式实现步骤

    SpringBoot返回统一的JSON标准格式实现步骤

    这篇文章主要介绍了SpringBoot返回统一的JSON标准格式,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-08-08
  • Java如何实现可折叠Panel方法示例

    Java如何实现可折叠Panel方法示例

    这篇文章主要给大家介绍了关于利用Java如何实现可折叠Panel的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用java具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-07-07
  • SpringBoot下载文件遇到文件损坏等问题解决方案

    SpringBoot下载文件遇到文件损坏等问题解决方案

    调用接口下载spring boot工程的resources目录下的excel模板文件,非常常见的一个文件下载功能,但是却容易遇到很多坑,下面总结记录下
    2023-10-10
  • 一个注解搞定Spring Security基于Oauth2的SSO单点登录功能

    一个注解搞定Spring Security基于Oauth2的SSO单点登录功能

    本文主要介绍 同域 和 跨域 两种不同场景单点登录的实现原理,并使用 Spring Security 来实现一个最简单的跨域 SSO客户端。对Spring Security基于Oauth2的SSO单点登录功能感兴趣的朋友一起看看吧
    2021-09-09
  • JavaWeb中struts2实现文件上传下载功能实例解析

    JavaWeb中struts2实现文件上传下载功能实例解析

    这篇文章主要介绍了JavaWeb中struts2文件上传下载功能的实现,在Web应用系统开发中,文件上传和下载功能是非常常用的功能,需要的朋友可以参考下
    2016-05-05
  • Java如何有效避免SQL注入漏洞的方法总结

    Java如何有效避免SQL注入漏洞的方法总结

    SQL注入是比较常见的网络攻击方式之一,它不是利用操作系统的BUG来实现攻击,而是针对程序员编程时的疏忽,通过SQL语句,实现无帐号登录,甚至篡改数据库,这篇文章主要给大家介绍了关于Java如何避免SQL注入漏洞的两种方法,需要的朋友可以参考下
    2022-01-01
  • Java实现递归山脉

    Java实现递归山脉

    这篇文章主要为大家详细介绍了Java实现递归山脉,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • java实现emqx设备上下线监听详解

    java实现emqx设备上下线监听详解

    这篇文章主要为大家介绍了java实现emqx设备上下线监听详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07

最新评论