【并发编程】多线程读写同一变量的并发问题(并发编程启动)

news2024/10/5 23:27:52

📫作者简介:小明java问道之路2022年度博客之星全国TOP3,专注于后端、中间件、计算机底层、架构设计演进与稳定性建设优化,文章内容兼具广度、深度、大厂技术方案,对待技术喜欢推理加验证,就职于知名金融公司后端高级工程师。

        

📫 热衷分享,喜欢原创~ 关注我会给你带来一些不一样的认知和成长。

        

🏆 2022博客之星TOP3 | CSDN博客专家 | 后端领域优质创作者 | CSDN内容合伙人

🏆 InfoQ(极客邦)签约作者、阿里云专家 | 签约博主、51CTO专家 | TOP红人、华为云享专家

        

🔥如果此文还不错的话,还请👍关注、点赞、收藏三连支持👍一下博主~ 


🍅 文末获取联系 🍅  👇🏻 精彩专栏推荐订阅收藏 👇🏻

专栏系列(点击解锁)

学习路线(点击解锁)

知识定位

🔥Redis从入门到精通与实战🔥

Redis从入门到精通与实战

围绕原理源码讲解Redis面试知识点与实战

🔥MySQL从入门到精通🔥

MySQL从入门到精通

全面讲解MySQL知识与企业级MySQL实战

🔥计算机底层原理🔥

深入理解计算机系统CSAPP

以深入理解计算机系统为基石,构件计算机体系和计算机思维

Linux内核源码解析

围绕Linux内核讲解计算机底层原理与并发

🔥数据结构与企业题库精讲🔥

数据结构与企业题库精讲

结合工作经验深入浅出,适合各层次,笔试面试算法题精讲

🔥互联网架构分析与实战🔥

企业系统架构分析实践与落地

行业最前沿视角,专注于技术架构升级路线、架构实践

互联网企业防资损实践

互联网金融公司的防资损方法论、代码与实践

🔥Java全栈白宝书🔥

精通Java8与函数式编程

本专栏以实战为基础,逐步深入Java8以及未来的编程模式

深入理解JVM

详细介绍内存区域、字节码、方法底层,类加载和GC等知识

深入理解高并发编程

深入Liunx内核、汇编、C++全方位理解并发编程

Spring源码分析

Spring核心七IOC/AOP等源码分析

MyBatis源码分析

MyBatis核心源码分析

Java核心技术

只讲Java核心技术

本文目录

本文目录

一、多线程读写共享变量问题

二、计算机内存模型

三、Java内存模型

四、总结


一、多线程读写共享变量问题

我们都知道,在多线程环境中访问相同的共享变量可能会导致线程安全问题,例如多个线程同时更新库存数据接口。

public class MallstockServiceImpl {

    int stockCount;

    /**
     *  扣库存,失败或者超时返回false
     */
    public boolean commonStockLogDeduct(StockLogDeductDTO req) {
        if (null == stockLogDeduct || !MallOrderConstant.SUC_CODE_00.equals(stockLogDeduct.getStatusKey())) {
            stockCount--;
        }
        return true;
    }
}

假设 MallstockServiceImpl 类中 stockCount 字段表示接口被扣减库存的次数, 每次访问接口的时候就调用一次 commonStockLogDeduct() 方法,库存数-1。

接口很可能被多个线程同时访问,即 commonStockLogDeduct() 方法被多个线程调用。那么多线程调用 commonStockLogDeduct() 方法时,接口访问次数统计的结果是否能保证准确呢?

假设类 MallstockServiceImpl 中的 stockCount 字段表示接口从库存中扣除的次数,则每次访问接口时调用 commonstocklog() 方法,扣除库存为-1。

具有一些并发编程经验的人可能还记得一个常见的场景,其中一个接口同时被多个线程访问,即多个线程调用当多个线程调用 commonStockLogDeduct() 方法时接口是否准确?

二、计算机内存模型

让我们首先简单地理解一下内存模型的概念,程序运行在Java虚拟机(JVM)上,JVM本身有自己的内存模型。

当计算机执行程序时,每条指令都在CPU中执行,执行指令的过程涉及到数据的读写操作,计算机在运行过程中,所有的数据都存储在主存中。CPU从主存中读取数据进行计算

由于CPU的执行速度非常快,比计算机主存的读写速度快得多,会造成CPU的执行速度大大降低,因此,每个CPU都有自己的高速缓冲区。

在操作过程中,要运行的数据将从计算机的主存储器复制到CPU的高速缓冲区。然后CPU将高速缓冲区中的数据执行操作,可以大大提高CPU的执行速度。

三、Java内存模型

JVM定义的内存模型与上面描述的内存模型有很多共同之处,除了JVM的内存模型掩盖了不同操作系统和底层硬件之间的内存访问差异,以实现跨平台的一致内存访问。

JVM启动后,操作系统为JVM进程分配一定的内存,称为主存Java程序的所有工作都是由线程完成的,并且每个线程都会有一小块内存,称为工作内存。

Java线程在执行过程中,会先将数据从主存复制到线程的工作内存中,然后再进行计算,计算完成后,再将计算结果刷新到主存中。

假设现在有两个线程同时访问了这个接口的 commonStockLogDeduct() 方法,两个线程都执行了stockCount--,在内存中是怎么样执行的呢?

首先我们要明白,计算机需要执行 stockCount-- 这个语句,需要分为以下3个步骤:

从主存中读取 stockCount 的值

将 stockCount 的值进行减 1

将 stockCount 的值写回主存中

首先线程1和线程2都会把 stockCount 的值从主存中复制到线程所属的工作内存中,两个线程此时得到的 stockCount 的值都是0,在工作内存中 stockCount 的值进行加1

线程1和线程2都进行了计算,然后线程1得到的结果是 stockCount =99,线程2得到的结果也是stockCount=99,接着将stockCount的值写回主存中。

但是无论是线程1还是线程2,写回主存的结果都是 stockCount =99。实际上,我们观察到是2个线程都执行了一次 commonStockLogDeduct() 方法,按照预期来说 stockCount 的值应该是等于98才对。

这种多个线程访问同一个对象时,调用这个对象的方法得到不正确的结果,这种问题称为线程安全问题。

四、总结

通过下单链路扣减库存引出了多线程并发访问共享变量的问题,接着简单介绍了一下计算机CPU内存模型,Java的内存模型,并基于Java的内存模型一步一图分析线程安全问题产生的原因。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

《动手学深度学习 Pytorch版》 10.1 注意力提示

10.1.1 生物学中的注意力提示 “美国心理学之父” 威廉詹姆斯提出的双组件(two-component)框架: 非自主性提示:基于环境中物体的突出性和易见性 自主性提示:受到了认知和意识的控制 10.1.2 查询、键和值 注意力机制…

一款功能强大的音乐曲谱软件Guitar Pro 8 .1.1for Mac 中文破解版

Guitar Pro 8 .1.1for Mac 中文破解版是一款功能强大的音乐曲谱软件,非常适合学习如何玩,改进技巧,重现喜爱的歌曲或陪伴自己。可以帮助我们进行吉他的学习、绘谱与创作,它包含了几乎所有的吉他现有指法及音色,在做弹拨…

C语言求 3*3 矩阵对角线之和

完整代码&#xff1a; // 求 3*3 矩阵对角线之和 #include<stdio.h>int main() {int n3;int arr[3][3];// 输入矩阵printf("请输入矩阵的元素:\n");for (int i 0; i < n; i){for (int j 0; j < n; j){scanf("%d", &arr[i][j]);}}int su…

OpenCV官方教程中文版 —— 图像金字塔

OpenCV官方教程中文版 —— 图像金字塔 前言一、原理二、使用金字塔进行图像融合 前言 • 学习图像金字塔 • 使用图像创建一个新水果&#xff1a;“橘子苹果” • 将要学习的函数有&#xff1a;cv2.pyrUp()&#xff0c;cv2.pyrDown()。 一、原理 一般情况下&#xff0c;我…

【Ubuntu18.04】激光雷达与相机联合标定(Livox+HIKROBOT)(一)

LivoxHIKROBOT联合标定 引言1 海康机器人HIKROBOT SDK二次开发并封装ROS1.1 介绍1.2 安装MVS SDK1.3 封装ROS packge 2 览沃Livox SDK二次开发并封装ROS3 相机雷达联合标定3.1 环境配置3.1.1 安装依赖——PCL 安装3.1.2 安装依赖——Eigen 安装3.1.3 安装依赖——Ceres-solver …

计算机视觉-数学基础*变换域表示

被研究最多的图像&#xff08;或任何序列数据&#xff09;变换域表示是通过傅 里叶分析 。所谓的傅里叶表示就是使用 正弦函数的线性组合来表示信号。对于一个给定的图像I(n1,n2) &#xff0c;可以用如下方式分解它&#xff08;即逆傅里叶变换&#xff09;&#xff1a; 其中&a…

浅谈APP自动化测试工具主要优势

移动应用程序已经成为我们日常生活和商业活动的重要组成部分。随着用户对应用性能、稳定性和用户体验的需求不断增加&#xff0c;开发人员不得不寻找方法来确保他们的应用在各种情况下都能正常运行。这就引入了自动化测试工具&#xff0c;这些工具通过自动执行测试用例来检查应…

openGauss学习笔记-107 openGauss 数据库管理-管理用户及权限-三权分立

文章目录 openGauss学习笔记-107 openGauss 数据库管理-管理用户及权限-三权分立107.1 默认的用户权限107.2 三权分立较非三权分立权限变化说明 openGauss学习笔记-107 openGauss 数据库管理-管理用户及权限-三权分立 默认权限机制和管理员两节的描述基于的是openGauss创建之初…

2023-10-23 LeetCode每日一题(老人的数目)

2023-10-23每日一题 一、题目编号 2678. 老人的数目二、题目链接 点击跳转到题目位置 三、题目描述 给你一个下标从 0 开始的字符串 details 。details 中每个元素都是一位乘客的信息&#xff0c;信息用长度为 15 的字符串表示&#xff0c;表示方式如下&#xff1a; 前十…

Java,回形数

回形数基本思路&#xff1a; 用不同的四个分支分别表示向右向下向左向上&#xff0c;假如i表示数组的行数&#xff0c;j表示数组的列数&#xff0c;向右向左就是控制j的加减&#xff0c;向上向下就是控制i的加减。 class exercise {public static void main(String[] args){//回…

Jenkins 重新定义 pom 内容,打包

文章目录 源码管理构建 源码管理 添加仓库地址&#xff0c;拉取凭证&#xff0c;选择需要的分支 构建 勾选 构建环境 下删除原始 build 配置&#xff0c;防止文件错误 Pre Steps 构建前处理 pom.xml &#xff0c;例如我是需要删除该模块的所有子模块配置&#xff0c;我这里…

超声波清洗机频率如何选择?高频和低频有什么区别

超声波清洗原理就是在清洗液中产生“空化效应”&#xff0c;即清洗液产生拉伸和压缩现象&#xff0c;清洗液拉伸时会产生大量微小气泡&#xff0c;清洗液压缩时气泡会被压碎破裂。这些气泡产生和破裂的局部压强可达到上千个大气压的冲击力&#xff0c;这种极强大的压力足以使得…

切片不够技术来凑

概述 随着数据经度的提升&#xff0c;18级的切片有些场景已经不够用了&#xff0c;但是大部分在线的栅格切片最大级别还是18级&#xff0c;如果地图继续放大&#xff0c;有的框架&#xff08;leaflet会&#xff0c;openlayers和mapboxGL不会&#xff09;会存在没有底图的情况。…

Spring源码篇(十二)事件机制

文章目录 前言应用示例第一种&#xff1a;EventListener第二种&#xff1a;实现ApplicationListener第三种&#xff1a;TransactionalEventListener补充&#xff1a;筛选条件 源码初始化事件器注册监听器添加监听器添加1&#xff1a;应用启动前的监听器SpringApplication实例化…

Hadoop3教程(三十五):(生产调优篇)HDFS小文件优化与MR集群简单压测

文章目录 &#xff08;168&#xff09;HDFS小文件优化方法&#xff08;169&#xff09;MapReduce集群压测参考文献 &#xff08;168&#xff09;HDFS小文件优化方法 小文件的弊端&#xff0c;之前也讲过&#xff0c;一是大量占用NameNode的空间&#xff0c;二是会使得寻址速度…

【Linux】进程优先级|进程并发概念|在vim中批量化注释

文章目录 前言tips——如何在vim中批量化注释进程更深度理解一、什么是进程优先级二、 为什么要有优先级三、Linux怎么设置优先级查看进程优先级的命令PRI and NI用top命令更改已存在进程的nice&#xff1a; 如何根据优先级开展调度呢&#xff1f;五、其他概念并发&#xff08;…

使用Github.io创建自己的博客

文章目录 1.最终效果2.操作步骤2.1 前置操作2.2 按照自己需求修改内容2.2.1 基本修改2.2.2 额外添加知乎等社交网站链接 2.3 首页修改2.4 查看发布状态2.5 奇怪的错误(头像显示错误)2.6 本地调试2.7 后续修改 3. 项目设置为私密&#xff08;要付费升级账号才行❌&#xff09;3.…

【BA-BP分类】基于蝙蝠算法优化神经网络分类研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

RHCE---Shell基础 2

文章目录 目录 文章目录 前言 一.变量 概述 定义 自定义变量 环境变量 概述&#xff1a; 定义环境变量&#xff1a; 位置变量 "$*"会把所有位置参数当成一个整体&#xff08;或者说当成一个单词 变量的赋值和作用域 read 命令 变量和引号 变量的作用域 变…

Java SOAP 调用 C# 的WebService

Java SOAP 调用 C# 的WebService&#xff0c;C# 的WebService方法的创建可以参考上一篇文章。IntelliJ IDEA Community Edition 2021.2.3的idea64.exe新建项目&#xff0c;导入需要的jar&#xff0c;代码如下&#xff1a; import org.apache.axis.client.Service; import org.…