深入解析Java内存模型
一、背景
并发编程本质问题
是:CPU、内存以及IO三者之间的速度差异。CPU速度快于内存、内存访问速度又远远快于IO
,根据木桶理论
,程序性能取决于最慢的操作,即IO操作。这样会出现CPU和内存交互时,CPU性能无法被充分利用,内存与IO交互时,内存性能也存在部分损耗,单方面提升CPU或内存的性能是无效的。为了提升CPU或内存的利用率,需要平衡三者的速度差异,计算机系统结构、操作系统以及编译程序都做出了贡献,主要体现为:
1. 计算机体系结构:为CPU增加了缓存,均衡和内存的速度差异;
2. 操作系统:增加了进程和线程,便于分时复用CPU,均衡CPU与IO设备的速度差异;
3. 编译程序:优化CPU指令的执行顺序,使得缓存被更加合理的利用。
上述方案虽然很大程度上解决了程序的性能问题,但也带来了许多隐藏的并发问题,主要为:可见性问题
、原子性问题
以及有序性问题
。
可见性问题:
定义:
一个线程对共享变量的修改,另外一个线程能够立刻看到,即可见性
导致原因:
CPU缓存
详情解析:
在多CPU时代,每个CPU都有自己的缓存,当多个CPU缓存同一份共享变量的数据时,线程A修改了共享变量,但修改目前只在CPU的缓存生效,其他CPU缓存还未来得及获取新修改的数据,线程B读取共享变量,读取的数据是老数据,存在数据不一致问题。
原子性问题:
定义:
一个或多个操作在CPU执行过程中不被中断的特性,即原子性
导致原因:
多线程上下文切换
详情解析:
多线程底层执行是按照时间片来执行的,进行任务切换时,针对的是单个CPU指令,仅能保证单个CPU指令的原子性。而高级语言的一条语句,往往是由多个CPU指令完成。例如count += 1,至少需要三条指令:
1. 首先,将变量count加载到对应CPU的寄存器中;
2. 其次,在寄存器中执行 +1 操作;
3. 最后,将结果写入到内存中
若是线程A执行完指令1后,切换到线程B来执行 count += 1操作,线程B操作后count为2,但线程A中保存的count值仍是1,导致最后的结果为2,实际上应该为3。
Java中的原子操作有哪些:
1. 除long和double之外的基本类型(int, byte, boolean, short, char, float)的赋值操作;针对long操作,直接拆分成两个32位的写入操作。
2. 所有引用reference的赋值操作;
3. java.concurrent.Atomic.*包中所有类的原子操作。
原子操作 + 原子操作 != 原子操作【原子性对比:】
synchronized:不可中断锁,适合竞争不激烈,可读性好
Lock: 可中断,多样化同步,竞争激烈时能维持常态
Atomic: 竞争激烈时能维持常态,比Lock性能好;只能同步一个值
有序性问题:
定义:
有序性是指按照代码的先后顺序来执行,但编译器为了优化性能,可能会改变代码的执行顺序。例如:i = 1; j = 2 变成 j = 2; i = 1
导致原因:
编译优化
详情解析:
在Java领域存在一个双重检查创建单例对象的场景,创建对象JVM底层分为三个步骤:
1. 分配内存空间;
2. 在内存上初始化对象;
3. 将对象地址赋值给实例变量
此时进行了编译优化,将1,2,3变成了1,3,2。那么就会出现多线程访问时,某些线程获取的对象为null,出现空指针问题。
因此,为了解决出现的可见性、原子性以及有序性问题,Java给出了一套解决方案,即Java Memory Model,简称JMM
。
二、Java内存模型
为了解决可见性和有序性,直观上可以理解:禁用缓存和编译优化
,但程序的性能就无法保证。理想方案是:开发者按需禁用缓存和编译优化,因此Java做了两个方面的工作:
- 定义一种
抽象计算机模型
; - 定义
一系列规则
,来保证可见性和有序性。
2.1 定义
抽象计算机模型:
JMM定义了线程和主内存之间的抽象关系:线程之间共享的变量存储在主内存中,每个线程有一个私有的本地内存,每个本地内存中存储了共享变量的副本。其中本地内存[工作内存]是一个抽象概念,底层对应着缓存、寄存器以及硬件和编译器优化等。主内存和工作内存之间的规范为:
所有的共享变量都存储于主内存
:这里的变量值是实例变量、类变量以及数组,因为堆和方法区是线程共享的。(局部变量属于线程私有,不存在线程安全问题)工作内存
:每一个线程有自己的工作内存,工作内存中保留了被多个线程使用的变量的工作副本线程不能直接读写主内存中的变量
① 只能操作自己的工作内存中的变量,
② 然后再同步到主内存中工作内存的屏蔽性
:不同线程之间不能直接访问对方工作内存中的变量,线程之间的值传递需要通过主内存来完成。(可见性问题的罪魁祸首)
一系列规则:
volatile、synchronized和final三个关键字,以及六项Happens-Before规则。
2.2 规则
Happens-Before规则指的是:前面一个操作结果
对后续操作是可见的。下面为详细的规则:
单线程规则:
一个线程中的每个操作,happens-before于该线程的任意后续操作;监视器锁规则(synchronized):
对一个锁的解锁,happens-before于随后对这个锁的加锁;volatile变量规则:
对一个volatile修饰的变量的写,happens-before于随后对这个变量的读;传递性:
如果A happens-before B、 B happens-before C、则A happens-before C;线程start启动规则:
主线程A启动子线程B后,子线程B能够看到主线程在启动子线程B前的操作结果;线程join()规则
: 主线程A等待子线程B完成,当子线程B完成后,主线程能够看到子线程的操作结果。final规则
: 通过final修饰变量,告诉编译器着变量是不会发生改变的,可以尽情优化。
三、总结
上述解决了可见性和有序性问题,原子性问题通过互斥锁
可以完美解决。
相关文章:

深入解析Java内存模型
一、背景 并发编程本质问题是:CPU、内存以及IO三者之间的速度差异。CPU速度快于内存、内存访问速度又远远快于IO,根据木桶理论,程序性能取决于最慢的操作,即IO操作。这样会出现CPU和内存交互时,CPU性能无法被充分利用…...
python使用国内镜像源
使用格式 格式为:pip install 库名 -i 镜像地址(注意空格的存在) pip install pandas -i https://pypi.tuna.tsinghua.edu.cn/simple 推荐的镜像源: 清华大学(推荐):https://pypi.tuna.tsing…...

【动态规划】代码随想录算法训练营第四十六天 |139.单词拆分,关于多重背包,你该了解这些! ,背包问题总结篇!(待补充)
139.单词拆分 1、题目链接:. - 力扣(LeetCode) 2、文章讲解:代码随想录 3、题目: 给定一个非空字符串 s 和一个包含非空单词的列表 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词…...

WordPress建站入门教程:如何选择和设置固定链接结构?
我们成功搭建好WordPress网站后,发布的文章对应的URL地址默认是使用“日期和名称型”,即是网站域名跟着的是年月日,最后是文章标题,如http://www.yigujin.com/2024/03/06/免费响应式WordPress博客主题JianYue/ 为了让我们的文章U…...

一款好用的AI工具——边界AICHAT(三)
目录 3.23、文档生成PPT演示3.24、AI文档翻译3.25、AI翻译3.26、论文模式3.27、文章批改3.28、文章纠正3.29、写作助手3.30、文言文翻译3.31、日报周报月报生成器3.32、OCR-DOC办公文档识别3.33、AI真人语音合成3.34、录音音频总结3.35、域方模型市场3.36、模型创建3.37、社区交…...
编程示例: 矩阵的多项式计算以javascript语言为例
编程示例: 矩阵的多项式计算以javascript语言为例 国防工业出版社的《矩阵理论》一书中第一章第8个习题 试计算2*A^8-3*A^5A^4A^2-4I A[[1,0,2],[0,-1,1],[0,1,0]] 代码如下 <html> <head> <title> 矩阵乘法 </title> <script srcset.js ><…...
project generator 简单使用
文章目录 1 progen 资源2 使用简介2.1 安装2.2 添加 target(可选)2.3 替换 CMake 模板(可选)2.4 创建 progen 项目 3 总结 1 progen 资源 0)简介:progen(project-generator,项目生成…...

C语言 —— 图形打印
题目1: 思路: 如果我们要打印一个实心正方形,其实就是一个二维数组,i控制行,j控制列,行列不需要控制,arr[i][j]直接打印星号即可。 对于空心正方形,我们只需要控制行和列的条件&…...
Python基础学习(11)常用模块
文章目录 一、time二、random三、os四、sys五、json补充1:JSON字符串补充2:JSON字符串和字典的区别 六、hashlib Python基础学习(1)基本知识 Python基础学习(2)序列类型方法与数据类型转换 Python基础学习(3)进阶字符串(格式化输出) Python基础学习(4)散…...

嵌入式学习37-TCP并发模型
TCP并发模型: 1.TCP多线程模型: 缺点: 1.创建线程会带来 资源开销 2.能够实现的 并发量 比较有限 2.IO模型: 1.阻塞IO: 没有…...

C语言字符函数和字符串函数
前言 今天这篇博客咱们一起来认识一些特殊的函数,在编程的过程中,我们经常要处理字符和字符串,为了方便字符和字符串,C语言提供了一些库函数,让我们一起看看这些函数都有什么功能吧!!࿰…...
Go语言必知必会100问题-22 空切片与nil切片有区别吗?
空切片与nil切片有区别吗? 很多开发人员经常混淆nil切片和空切片,不清楚什么时候使用空切片什么时候使用nil,而有些库函数又对这两者使用进行了区分。下面先来看看它们的定义。 空切片是length为0的切片当切片等于nil时为nil切片 下面是几种不同空切片…...

【C++进阶】C++多态概念详解
C多态概念详解 一,多态概念二,多态的定义2.1 多态构成的条件2.2 什么是虚函数2.3 虚函数的重写2.3.1 虚函数重写的特例2.3.2 override和final 2.4 重载和重写(覆盖)和重定义(隐藏)的区别 三,抽象…...

Python 导入Excel三维坐标数据 生成三维曲面地形图(面) 2、线条平滑曲面但有间隔
环境和包: 环境 python:python-3.12.0-amd64包: matplotlib 3.8.2 pandas 2.1.4 openpyxl 3.1.2 scipy 1.12.0 代码: import pandas as pd import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D from scipy.interpolate import griddata imp…...

前端精准测试调用链路分析
精准测试在评估需求的测试范围时,需要评估一下代码的影响范围,这个范围有两部分:一是需求直接修改的代码;二是修改代码影响到的功能模块。代码影响到的功能一般是通过调用链路分析来实现的,java和kotlin代码可以由java…...

Objective-C blocks 概要
1.block的使用 1.1什么是block? Blocks是C语言的扩充功能:带有自动变量(局部变量)的匿名函数。 “带有自动变量”在Blocks中表现为“截取自动变量" “匿名函数”就是“不带名称的函数” 块,封装了函数调用及调用…...

Linux操作系统-07-Linux安装应用
一、使用rpm安装应用(不推荐) 先下载到本地,以.rpm文件名结尾,下载完成后,再安装 rpm -qa | grep mysql #查询当前系统是否有下载过mysql包 先上传mysql的rpm安装包到linux的opt目录 安装 rpm -ivh …...
DevOps实战:Docker、Kubernetes与Jenkins的完美融合
DevOps与容器化技术:Docker、Kubernetes和Jenkins 引言 在软件开发领域,DevOps文化和容器化技术已经成为当今最热门的话题之一。DevOps的目标是缩短开发和运维之间的距离,提高软件交付的速度和质量。而容器化技术,如Docker和Kub…...

Python面向对象——程序架构
需求 创建图形管理器 -记录多种图形(圆形、矩形.) --提供计算总面积的方法, 要求:增加新图形,不影响图形管理器 测试: 创建图形管理器,存储多个图形对象。 通过图形管理器,调用计算总面积方法 思路 代码 # ------…...
springboot单体项目链路日志跟踪及接口耗时
最近接触一个新的传统项目,在联调过程中,查看日志特别不方便,既无trackId,即无接口耗时,所以写了该博客。话不多说,直接上代码 1、实体类user package com.yk.domain;import lombok.Data;@Data public class User {private Long id;private String username;private St…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...

Redis相关知识总结(缓存雪崩,缓存穿透,缓存击穿,Redis实现分布式锁,如何保持数据库和缓存一致)
文章目录 1.什么是Redis?2.为什么要使用redis作为mysql的缓存?3.什么是缓存雪崩、缓存穿透、缓存击穿?3.1缓存雪崩3.1.1 大量缓存同时过期3.1.2 Redis宕机 3.2 缓存击穿3.3 缓存穿透3.4 总结 4. 数据库和缓存如何保持一致性5. Redis实现分布式…...
React Native在HarmonyOS 5.0阅读类应用开发中的实践
一、技术选型背景 随着HarmonyOS 5.0对Web兼容层的增强,React Native作为跨平台框架可通过重新编译ArkTS组件实现85%以上的代码复用率。阅读类应用具有UI复杂度低、数据流清晰的特点。 二、核心实现方案 1. 环境配置 (1)使用React Native…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...
docker 部署发现spring.profiles.active 问题
报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...

基于Java+MySQL实现(GUI)客户管理系统
客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息,对客户进行统一管理,可以把所有客户信息录入系统,进行维护和统计功能。可通过文件的方式保存相关录入数据,对…...

Windows安装Miniconda
一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...

解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用
在工业制造领域,无损检测(NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统,以非接触式光学麦克风技术为核心,打破传统检测瓶颈,为半导体、航空航天、汽车制造等行业提供了高灵敏…...