JMM内存模型 volatile关键字解析

前言

对于多线程等等的各种操作,相比各位都了然于胸,现在我们来介绍一下更底层一点点的JMM内存模型,其实也是一个很简单的理想的内存模型

注意与JVM的内存模型区分

多线程内存模型主要是基于CPU缓存搭建起来的

这里就区分工作内存和主内存了

我们线程操作的其实是主内存的一个副本,多线程每个线程操作结束了之后需要刷回主内存

volatile关键字 

我们知道volatile主要的两个功能就是

1.保证内存中的变量可见性

2.禁止指令重排序

下面我们来介绍一些关于volatile关键字以及高并发的内容

我们知道,如果两个线程同时操作一个变量,我们这里就称之为线程a和线程b,a线程假设操作了主内存的一个变量,另一个线程能感知到吗?

答案是不能,因为两者始终操作的是其工作内存中的变量副本而已.

如果这里我给共享的变量加入一个volatile关键字修饰,这里就b线程就能感知到工作内存中的变量变化了,这是为什么呢?

请听我慢慢解释

首先我们需要先了解一下经典的原子操作

然后我们来谈谈另一个线程是怎么感知到的

说到这里就不得不提我们的MESI(缓存一致性)协议了

这里就是线程a一修改主内存中的变量,其实这个修改是通过总线传输到主内存的

这里线程b就是通过总线嗅探机制,一直在监听总线,当他发现这里总线中有我的属性被修改了

这里我们的b线程对应的变量的属性就直接设置为I(无效),当下次线程b需要使用这个变量的时候哦,他就只能取主内存里面再去刷入工作内存了

那么我们的硬件协议又是怎么让缓存一致性协议生效的呢?

其本质就是在其底层的汇编代码前面加上了lock前缀

注意这里是修改完直接就同步回主内存,主打一个即时性

关于这里的指令重排序,我们也来谈一谈

为什么指令重排序

这里的指令重排序主要是为了加快程序性能而产生的

遵循 happens before 和 as is serial 原则

本质上就是在下面一条语句依赖于上面一条语句的时候

不会执行指令重排序,不影响依赖关系就随便排序

注:java 在执行代码之前会看看语法树前后有没有相互依赖

下面我展示部分原则

懒汉模式出现的对象半初始化问题

我们知道懒汉模式这里会使用双重校验锁

我拿出了其两行字节码指令

假设这里的putstatic在init之前

这里刚刚putstatic之后,cpu就调度到另一个线程了

这里判断已经不是空了,直接拿来使用,就会发生意想不到的问题

假设我这里a开了一个账户充6000块,然后直接去消费了

结果消费的时候发现账户的前不翼而飞了,所以这里的指令重排序问题是一个大的问题

常见的几种内存屏障

我们都知道volatile关键字是底层实现其实是一些内存屏障来实现的

我这里贴出几种常见的内存屏障

然后我们可以查看一下Java具体是怎么实现的

我们以 openjdk8 根路径 jdk\src\hotspot\share\interpreter\zero 路径下的 bytecodeInterpreter.cpp 文件中,处理 putstatic 指令的代码:

先进行判断是否有volatile修饰的实例

然后判断是对于不同的修饰类型进行操作

CASE(_putstatic):{// .... 省略若干行 // Now store the result 现在要开始存储结果了// ConstantPoolCacheEntry* cache;     -- cache是常量池缓存实例// cache->is_volatile()               -- 判断是否有volatile访问标志修饰int field_offset = cache->f2_as_index();// ****重点判断逻辑**** if (cache->is_volatile()) { // volatile变量的赋值逻辑if (tos_type == itos) {obj->release_int_field_put(field_offset, STACK_INT(-1));} else if (tos_type == atos) {// 对象类型赋值VERIFY_OOP(STACK_OBJECT(-1));obj->release_obj_field_put(field_offset, STACK_OBJECT(-1));OrderAccess::release_store(&BYTE_MAP_BASE[(uintptr_t)obj >> CardTableModRefBS::card_shift], 0);} else if (tos_type == btos) {// byte类型赋值obj->release_byte_field_put(field_offset, STACK_INT(-1));} else if (tos_type == ltos) {// long类型赋值obj->release_long_field_put(field_offset, STACK_LONG(-1));} else if (tos_type == ctos) {// char类型赋值obj->release_char_field_put(field_offset, STACK_INT(-1));} else if (tos_type == stos) {// short类型赋值obj->release_short_field_put(field_offset, STACK_INT(-1));} else if (tos_type == ftos) {// float类型赋值obj->release_float_field_put(field_offset, STACK_FLOAT(-1));} else {// double类型赋值obj->release_double_field_put(field_offset, STACK_DOUBLE(-1));}// *** 写完值后的storeload屏障 ***OrderAccess::storeload();} else {// 非volatile变量的赋值逻辑}       }

我们看到这里判断完的的storeload

然后我们介绍一下这个fence函数

这里先判断使用的显卡还是其他显卡

其实没有什么区别,主要是amd使用rsp,其他显卡使用的是esp,使用的寄存器不同

inline void OrderAccess::fence() {// always use locked addl since mfence is sometimes expensive// 
#ifdef AMD64__asm__ volatile ("lock; addl $0,0(%%rsp)" : : : "cc", "memory");
#else__asm__ volatile ("lock; addl $0,0(%%esp)" : : : "cc", "memory");
#endifcompiler_barrier();
}

这个__asm__就是表示告诉编译器在这里插入汇编代码

volatile就是告诉编译器我这里插入的汇编代码原原本本的给我执行,不许重排序

我们发现这些名字前面都有一个lock就是会将这块内存区域的缓存锁定并写回到主内存中

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

构建第一个JS应用(FA模型)

创建JS工程 若首次打开DevEco Studio,请点击Create Project创建工程。如果已经打开了一个工程,请在菜单栏选择File > New > Create Project来创建一个新工程。选择Application应用开发(本文以应用开发为例,Atomic Service对…

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单视频处理实战案例 之一 简单视频放大抖动效果

Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单视频处理实战案例 之一 简单视频放大抖动效果 目录 Python 基于 OpenCV 视觉图像处理实战 之 OpenCV 简单视频处理实战案例 之一 简单视频放大抖动效果 一、简单介绍 二、简单视频放大抖动效果实现原理 三、简单视频放大…

R语言数据挖掘:随机森林(1)

数据集heart_learning.csv与heart_test.csv是关于心脏病的数据集,heart_learning.csv是训练数据集,heart_test.csv是测试数据集。要求:target和target2为因变量,其他诸变量为自变量。用决策树模型对target和target2做预测&#xf…

OpenHarmony实战开发-多设备自适应能力

介绍 本示例是《一次开发,多端部署》的配套示例代码,展示了页面开发的一多能力,包括自适应布局、响应式布局、典型布局场景以及资源文件使用。 说明: 自适应布局能力仅可以保证在外部容器大小在一定范围内变化时,容…

Vue项目中 安装及使用Sass(scss)

普通方法 一、安装使用scss 1. 安装 scss npm install scss --save2. 安装 node-sass 和 sass-loader sass-loader:把 sass编译成css node-sass:nodejs环境中将sass转css 提示:限制 node-sass,sass-loader 版本号,…

【协议篇:Http与Https】

1. Http 1.1 Http的定义 超文本传输协议(Hypertext Transfer Protocol,HTTP)是用于分布式、协作式和超媒体信息系统的应用层协议。它是互联网上最广泛应用的数据通信协议之一,尤其对于万维网(WWW)服务而言…

构建第一个ArkTS应用(FA模型)

创建ArkTS工程 若首次打开DevEco Studio,请点击Create Project创建工程。如果已经打开了一个工程,请在菜单栏选择File > New > Create Project来创建一个新工程。选择Application应用开发(本文以应用开发为例,Atomic Servi…

推理端框架简介 高通SNPE 神经网络处理引擎 阿里巴巴 MNN 腾讯 FeatherCNN 端侧推理引擎 卷积计算优化 卷积计算优化

高性能计算(High performance computing, 缩写HPC) 指通常使用很多处理器(作为单个机器的一部分) 或者某一集群中组织的几台计算机(作为单个计 算资源操作)的计算系统和环境。 有许多类型的HPC 系统,其范围从标准计算机的大型集群,到高度专用的硬件。 大多数基于集群的H…

网站如何运用百度文心一言API进行AI内容创作?

网站如何运用百度文心一言API进行AI内容创作? 当我们做好一个网站的时候会因为创作内容而发愁,随着chatgpt的出现,内容创作已经不再是什么困难的事情,但是由于gpt是国外的,在国内使用有诸多不便,因此我们今…

【flutter封装图片/视频选择控件】

引入库 wechat_assets_picker: ^6.0.5 、video_player: ^2.5.1 # 视频播放、 flutter_screenutil: ^5.7.0 import dart:async; import dart:io; import package:generated/l10n.dart; import package:jade/configs/PathConfig.dart; import package:jade/customWidget/addImag…

数据质量决定大模型能力,景联文科技提供高质量大模型数据

随着大模型的深入发展,各类资源要素的配置状态已悄然变化。其中,数据的价值已被提升到一个新高度。 大模型往往拥有庞大的参数和复杂的网络结构,需要大量的数据来学习和优化。数据的质量和数量直接决定了模型的训练效果。若数据不足或质量不佳…

React + 项目(从基础到实战) -- 第三期

react内置hooks useState 如何让页面动起来(实时更新) import React,{FC,useState} from "react";const Demo:FC()>{let count0; //普通js变量无法触发组件更新function add(){count;console.log("count: ",count);}return <div><button onCl…

远程登录服务器(ubuntu20.04)在自己账号下的虚拟环境(python3.6)安装Jupyter并连接pycharm使用

参考&#xff1a;Jupyter notebook/lab安装及远程访问 1、安装jupyter pip install notebook遇到的问题&#xff1a; &#xff08;1&#xff09;运行这个指令之前尝试了好多方法都安不上 此前还尝试了更新pip之类的&#xff0c;大家安不上也可以先更新pip试试。 &#xff0…

JavaScript简介

目录 概要&#xff1a; 说明&#xff1a; 学习JS的原因&#xff1a; JS可以干什么&#xff1a; 了解JavaScript&#xff1a; 前言&#xff1a; JavaScript的历史&#xff1a; JavaScript与ECMAScript&#xff1a; 如何运行JavaScript以及JavaScrip的特点&#xff1a; …

基于Python的微博旅游情感分析、微博舆论可视化系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

HTML - 你知道b与strong标签的区别吗

难度级别&#xff1a;初级及以上 提问概率&#xff1a;50% 不单单是初学者&#xff0c;即便是有好几年工作经验的前端开发工作者&#xff0c;也会有一大部分人把这两个标签搞混&#xff0c;甚至在工作中&#xff0c;很大一部人不会使用这两个标…

玩转Django分页器

一、Pagination 分页器编程步骤 View, 导入django.core.paginator.Paginator类&#xff0c;创建Paginator 对象时&#xff0c;输入qs对象&#xff0c;以及每页显示条数。 接收 URL, 从请求参数中读取page数值 &#xff0c;通过 paginator.page(page_num) 返回请求页的page_obj…

电商好评语整理与优化:让繁琐工作变得轻松高效

在电子商务领域&#xff0c;客户的好评是店铺信誉和产品质量的重要体现。然而&#xff0c;整理和优化这些好评语却是一项既繁琐又需要细致耐心的工作。本文将探讨如何高效地进行电商好评语的筛选、分类和优化&#xff0c;让这一工作变得更加轻松和高效。 一、明确整理目的 在开…

环保用电监测系统诞生与作用

随着全球能源危机的加剧和环境保护意识的提高&#xff0c;环保用电监测系统应运而生。这一系统以其独特的监测能力、数据分析和节能减排功能&#xff0c;在提高用电效率和促进环境可持续发展方面发挥着重要作用。本文将从环保用电监测系统的诞生背景、主要功能、作用以及在实际…

语音识别:基于HMM

HMM语音识别的解码过程 从麦克风采集的输入音频波形被转换为固定尺寸的一组声学向量&#xff1a; 其中是维的语音特征向量&#xff08;例如MFCC&#xff09;。 解码器尝试去找到上述特征向量序列对应的单词&#xff08;word&#xff09;的序列&#xff1a; 单词序列的长度是。…