【JVM】一篇通关JMM内存模型

JMM内存模型

  • 1. 原子性
    • 1-1. 问题分析
    • 1-2. 问题解决
  • 2. 可见性
    • 2-1. 问题分析
    • 2-2. 问题解决
  • 3. 有序性
    • 3-1. 问题分析
    • 3-2. 问题解决
  • 4. CAS与原子性
  • 5. synchronized 优化

1. 原子性

  • 很多人将【java 内存结构】与【java 内存模型】傻傻分不清,【java 内存模型】是 Java Memory Model(JMM)的意思。
  • 简单的说,JMM 定义了一套在多线程读写共享数据时(成员变量、数组)时,对数据的可见性有序性、和原子性的规则和保障

1-1. 问题分析

两个线程对初始值为 0 的静态变量一个做自增,一个做自减,各做 5000 次,结果是 0 吗?

  • 结果可能是正数、负数、零。为什么呢?因为 Java 中对静态变量的自增,自减并不是原子操作。

例如对于 i++ 而言(i 为静态变量),实际会产生如下的 JVM 字节码指令:

getstatic i // 获取静态变量i的值
iconst_1 // 准备常量1
iadd // 加法
putstatic i // 将修改后的值存入静态变量i

而对应 i-- 也是类似:

getstatic i // 获取静态变量i的值
iconst_1 // 准备常量1
isub // 减法
putstatic i // 将修改后的值存入静态变量i

而 Java 的内存模型如下,完成静态变量的自增,自减需要在主存线程内存中进行数据交换:

在这里插入图片描述

1-2. 问题解决

synchronized(同步关键字)

synchronized( 对象 ) {
    要作为原子操作代码
}

2. 可见性

2-1. 问题分析

先来看一个现象,main 线程对 run 变量的修改对于 t 线程不可见,导致了 t 线程无法停止:

static boolean run = true;
public static void main(String[] args) throws InterruptedException {
    Thread t = new Thread(()->{
        while(run){
            // ....
        }
    });
    t.start();
    Thread.sleep(1000);
    run = false; // 线程t不会如预想的停下来
}

为什么会这样?

  1. 初始状态, t 线程刚开始从主内存读取了 run 的值到工作内存。

在这里插入图片描述
2. 因为 t 线程要频繁从主内存中读取 run 的值,JIT 编译器会将 run 的值缓存至自己工作内存中的高速缓存中,减少对主存中 run 的访问,提高效率

在这里插入图片描述
3. 1 秒之后,main 线程修改了 run 的值,并同步至主存,而 t 是从自己工作内存中的高速缓存中读取这个变量的值,结果永远是旧值

在这里插入图片描述

2-2. 问题解决

volatile(易变关键字)

它可以用来修饰成员变量和静态成员变量,他可以避免线程从自己的工作缓存中查找变量的值,必须到主存中获取它的值,线程操作 volatile 变量都是直接操作主存,保证了共享变量的可见性,但不能保证原子性

public class Demo1 {
    volatile static boolean run = true;

    public static void main(String[] args) throws InterruptedException {
        Thread t = new Thread(() -> {
            while (run) {
// ....
            }
        });
        t.start();
        Thread.sleep(1000);
        run = false; // 线程t不会如预想的停下来
    }

}

注意:
synchronized 语句块既可以保证代码块的原子性,也同时保证代码块内变量的可见性。但 缺点是synchronized是属于重量级操作,性能相对更低
如果在前面示例的死循环中加入 System.out.println() 会发现即使不加 volatile 修饰符,线程 t 也 能正确看到对 run 变量的修改了,想一想为什么?

进入println源码:

public void println(int x) {
    synchronized (this) {
        print(x);
        newLine();
    }
}

可以看出加了synchronized,保证了每次run变量都会从主存中获取

3. 有序性

3-1. 问题分析

看下面一个栗子:

int num = 0;
boolean ready = false;
// 线程1 执行此方法
public void actor1(I_Result r) {
    if(ready) {
        r.r1 = num + num;
    } else {
        r.r1 = 1;
    }
}
// 线程2 执行此方法
public void actor2(I_Result r) {
    num = 2;
    ready = true;
}

看到这里可能聪明的小伙伴会想到有下面三种情况:

情况1:线程1 先执行,这时 ready = false,所以进入 else 分支结果为 1

情况2:线程2 先执行 num = 2,但没来得及执行 ready = true,线程1 执行,还是进入 else 分支,结果为1

情况3:线程2 执行到 ready = true,线程1 执行,这回进入 if 分支,结果为 4(因为 num 已经执行过了)

但其实还有可能为0哦!😲

有可能还是:线程 2 执行 ready=true ,切换到线程1 ,进入if分支,相加为0,在切回线程 2 执行 num=2

这种现象就是指令重排

3-2. 问题解决

volatile 修饰的变量,可以禁用指令重排

int num = 0;
volatile boolean ready = false;
// 线程1 执行此方法
public void actor1(I_Result r) {
    if(ready) {
        r.r1 = num + num;
    } else {
        r.r1 = 1;
    }
}
// 线程2 执行此方法
public void actor2(I_Result r) {
    num = 2;
    ready = true;
}

4. CAS与原子性

5. synchronized 优化

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/280699.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【模拟电路】常见电学定律 戴维宁定理、诺顿定理、基尔霍夫定律

一、戴维宁定理 二、诺顿定理 三、基尔霍夫定律 一、戴维宁定理 任何复杂电路可以等效为一个电压源和一个电阻器组成 德维宁定理(Thevenin’s Theorem)是电路理论中的一个基本定理,它提供了一种简化复杂线性电路的方法。德维宁定理的主要思…

【网络安全】网络隔离设备

一、网络和终端隔离产品 网络和终端隔离产品分为终端隔离产品和网络隔离产品两大类。终端隔离产品一般指隔离卡或者隔离计算机。网络隔离产品根据产品形态和功能上的不同,该类产品可以分为协议转换产品、网闸和网络单向导入产品三种。 图1为终端隔离产品的一个典型…

机器学习系列13:通过随机森林获取特征重要性

我们已经知道通过 L1 正则化和 SBS 算法可以用来做特征选择。 我们还可以通过随机森林从数据集中选择相关的特征。随机森林里面包含了多棵决策树,我们可以通过计算特征在每棵决策树决策过程中所产生的的信息增益平均值来衡量该特征的重要性。 你可能需要参考&…

用IDEA创建/同步到gitee(码云)远程仓库(保姆级详细)

前言: 笔者最近在学习java,最开始在用很笨的方法:先克隆远程仓库到本地,再把自己练习的代码从本地仓库上传到远程仓库,很是繁琐。后发现可以IDEA只需要做些操作可以直接把代码上传到远程仓库,也在网上搜了些…

2023年03月22日_腾讯2022年财报解读

文章目录 1 - 腾讯营收增长停滞2 - 腾讯游戏业务低迷3 - 小程序和视频号拉动广告增长4 - 腾讯云和金融科技表现不佳5 - 营销费用减半6 - 裁员但福利上涨 2023年03月22日 今天晚上呢 腾讯披露了2022年第四季度和全年的财报 看过之后呢不禁要说 腾讯在2022年真的是过得不容易啊…

简单vlan划分和dhcp中继(Cisco Packet Tracer模拟)

文章目录 1. 前言2. 功能实现2.1. dhcp服务器接入2.2. 学校web服务器2.3. 设置学校dns服务器2.4. 设置线路冗余2.5. 配置ac。 1. 前言 在这里我们的计网作业是使用思科的Cisco Packet Tracer进行对校园网的简单规划,这里我对校园网进行了简单的规划,功能…

IDEA JAVA Spring Boot运行Hello World(1.8)

参考资料: Spring Boot运行Hello World - 知乎https://blog.csdn.net/weixin_44005516/article/details/108293228(解决bug)SpringBoot入门第一章:Hello World-java教程-PHP中文网 (仅参考如何运行程序)java 8安装教程 java 8安装教程_java8安装-CSDN博…

数据结构(五)——初识线性表

🧑个人简介:大家好,我是尘觉,希望我的文章可以帮助到大家,您的满意是我的动力😉 在csdn获奖荣誉: 🏆csdn城市之星2名 ⁣⁣⁣⁣ ⁣⁣⁣⁣ ⁣⁣⁣⁣ ⁣⁣⁣⁣ ⁣⁣⁣⁣ ⁣⁣⁣⁣ ⁣⁣⁣⁣ …

C#语言发展历程(1-7)

一、类型发展 C#1中是没有泛型的 在C#2中在逐渐推出泛型。C#2还引入了可空类型。 示例:C#泛型(详解)-CSDN博客 1 C#3:引入了匿名类型、和隐式的局部变量(var) 匿名类型:我们主要是使用在LIN…

宠物救助上门喂养系统宠物领养宠物寄养寻宠小程序宠物社区系统宠物托运宠物殡葬源码

后端php 前端uniapp mysql数据库 主要功能介绍: 1.根据当前位置 支持多城市切换 2.支持首页公告实时显示 3.支持 宠物救助,上门喂养,宠物领养,宠物寄养,寻宠,宠物社区,宠物托运&#xff…

SpringAMQP的使用方式

MQ介绍 MQ,中文是消息队列(MessageQueue),字面来看就是存放消息的队列。也就是事件驱动架构中的Broker。 比较常见的MQ实现: ActiveMQ RabbitMQ RocketMQ Kafka 几种常见MQ的对比: RabbitMQActiveM…

django基础学习

django基础学习 文章目录 django基础学习django框架urls.py将请求发送到正确的视图views.py处理请求models.py定义数据模型根据models查询数据HTML模板呈现数据 Django项目结构创建虚拟环境下载django创建站点创建应用settings.py项目设置 通用类别视图会话框架身份验证视图使用…

探索 Pinia:简化 Vue 状态管理的新选择(上)

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云…

项目中使用Java中List.subList()的注意事项

使用介绍 在Java中&#xff0c;subList是List接口的一个方法&#xff0c;用于获取原始列表的子列表 方法的声明如下 List<E> subList(int fromIndex, int toIndex);fromIndex&#xff1a;起始索引&#xff08;包括&#xff09;toIndex&#xff1a;结束索引&#xff08…

dash 中的模式匹配回调函数Pattern-Matching Callbacks 8

模式匹配 模式匹配回调选择器 MATCH、ALL 和 ALLSMALLER 允许您编写可以响应或更新任意或动态数量组件的回调函数。 此示例呈现任意数量的 dcc. Dropdown 元素&#xff0c;并且只要任何 dcc. Dropdown 元素发生更改&#xff0c;就会触发回调。尝试添加几个下拉菜单并选择它们的…

Java项目:101SpringBoot仓库管理系统

博主主页&#xff1a;Java旅途 简介&#xff1a;分享计算机知识、学习路线、系统源码及教程 文末获取源码 一、项目介绍 仓库管理系统基于SpringBootMybatis开发&#xff0c;系统使用shiro框架做权限安全控制&#xff0c;超级管理员登录系统后可根据自己的实际需求配角色&…

(四)开启定时器2中断

文章目录 定时器2中断的开启借用isp软件生成代码下面进行定时器2中断开启 最终开启定时器2中断的代码定时器2中断服务函数的编写查手册得到定时器2中断查询次序号查手册得次序号为12通过公式计算 中断服务函数编写 结合之前学的点亮LED现象演示 定时器2中断的开启 借用isp软件…

【开源】基于Vue+SpringBoot的二手车交易系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 二手车档案管理模块2.3 车辆预约管理模块2.4 车辆预定管理模块2.5 车辆留言板管理模块2.6 车辆资讯管理模块 三、系统设计3.1 E-R图设计3.2 可行性分析3.2.1 技术可行性分析3.2.2 操作可行性3.2.3 经济…

大模型推理部署:LLM 七种推理服务框架总结

自从ChatGPT发布以来&#xff0c;国内外的开源大模型如雨后春笋般成长&#xff0c;但是对于很多企业和个人从头训练预训练模型不太现实&#xff0c;即使微调开源大模型也捉襟见肘&#xff0c;那么直接部署这些开源大模型服务于企业业务将会有很大的前景。 本文将介绍七中主流的…

git基础概念和常用命令(日常开发收藏备用)

目录 ### 常用命令 ### 远程仓库与克隆 ### 分支管理 ### 子模块&#xff08;Submodule&#xff09; ### 其他高级操作 ### 交互式暂存&#xff08;Interactive Staging&#xff09; ### cherry-pick ### rebase ### reflog与reset ### 子树合并&#xff08;Subtree …