Java并发(十三)----共享存在的问题

1、小故事

  • 老王(操作系统)有一个功能强大的算盘(CPU),现在想把它租出去,赚一点外快

  • 小南、小女(不同的线程)来使用这个算盘来进行一些计算,并按照时间给老王支付费用

  • 但小南不能一天24小时使用算盘,他经常要小憩一会(sleep),又或是去吃饭上厕所(阻塞 io 操作),有时还需要一根烟,没烟时思路全无(wait)这些情况统称为(阻塞)

  • 在这些时候,算盘没利用起来(不能收钱了),老王觉得有点不划算

  • 另外,小女也想用用算盘,如果总是小南占着算盘,让小女觉得不公平

  • 于是,老王灵机一动,想了个办法 [ 让他们每人用一会,轮流使用算盘 ]

  • 这样,当小南阻塞的时候,算盘可以分给小女使用,不会浪费,反之亦然

  • 最近执行的计算比较复杂,需要存储一些中间结果,而学生们的脑容量(工作内存)不够,所以老王申请了一个笔记本(主存),把一些中间结果先记在本上

  • 计算流程是这样的

  • 但是由于分时系统,有一天还是发生了事故

  • 小南刚读取了初始值 0 做了个 +1 运算,还没来得及写回结果

  • 老王说 [ 小南,你的时间到了,该别人了,记住结果走吧 ],于是小南念叨着 [ 结果是1,结果是1...] 不甘心地到一边待着去了(上下文切换)

  • 老王说 [ 小女,该你了 ],小女看到了笔记本上还写着 0 做了一个 -1 运算,将结果 -1 写入笔记本

  • 这时小女的时间也用完了,老王又叫醒了小南:[小南,把你上次的题目算完吧],小南将他脑海中的结果 1 写入了笔记本

  • 小南和小女都觉得自己没做错,但笔记本里的结果是 1 而不是 0

2、Java 的体现

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

static int counter = 0;
​
public static void main(String[] args) throws InterruptedException {
    Thread t1 = new Thread(() -> {
        for (int i = 0; i < 5000; i++) {
            counter++;
        }
    }, "t1");
​
    Thread t2 = new Thread(() -> {
        for (int i = 0; i < 5000; i++) {
            counter--;
        }
    }, "t2");
​
    t1.start();
    t2.start();
    t1.join();
    t2.join();
    log.debug("{}",counter);
}

多做几次实验,可以得出答案明显不全是0。

3、问题分析

以上的结果可能是正数、负数、零。为什么呢?因为 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 的内存模型如下,完成静态变量的自增,自减需要在主存和工作内存中进行数据交换: 

如果是单线程以上 8 行代码是顺序执行(不会交错)没有问题:

但多线程下这 8 行代码可能交错运行:

出现负数的情况:

出现正数的情况:

4、临界区 Critical Section

  • 一个程序运行多个线程本身是没有问题的

  • 问题出在多个线程访问共享资源

    • 多个线程读共享资源其实也没有问题

    • 在多个线程对共享资源读写操作时发生指令交错,就会出现问题

  • 一段代码块内如果存在对共享资源的多线程读写操作,称这段代码块为临界区

例如,下面代码中的临界区

static int counter = 0;
​
static void increment() 
// 临界区
{    
    counter++;
}
​
static void decrement() 
// 临界区
{    
    counter--;
}

5、竞态条件 Race Condition

多个线程在临界区内执行,由于代码的执行序列不同而导致结果无法预测,称之为发生了竞态条件

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

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

相关文章

neo4j教程-安装部署

neo4j教程-安装部署 Neo4j的关键概念和特点 •Neo4j是一个开源的NoSQL图形存储数据库&#xff0c;可为应用程序提供支持ACID的后端。Neo4j的开发始于2003年&#xff0c;自2007年转变为开源图形数据库模型。程序员使用的是路由器和关系的灵活网络结构&#xff0c;而不是静态表…

【代码随想录 | Leetcode | 第十一天】字符串 | 反转字符串 | 反转字符串 II | 替换空格 | 反转字符串中的单词 | 左旋转字符串

前言 欢迎来到小K的Leetcode|代码随想录|专题化专栏&#xff0c;今天将为大家带来字符串~反转字符串 | 反转字符串 II | 替换空格 | 反转字符串中的单词 | 左旋转字符串的分享✨ 目录 前言344. 反转字符串541. 反转字符串 II剑指 Offer 05. 替换空格151. 反转字符串中的单词剑…

MATLAB与ROS联合仿真——实例程序搭建思路

一、基础运动控制实例程序搭建思路 1、需要完成的任务&#xff1a; &#xff08;1&#xff09;通过设定小车运动的速度及转角来控制ROS中小车运动。 &#xff08;2&#xff09;通过键盘输入指令控制ROS中小车运动&#xff0c;键盘输入w小车前行&#xff0c;s小车后退&#x…

Windows Server 2012 搭建网关服务器并端口转发

需求 使用 Windows server 作为Hyper-V 虚拟出许多虚拟机&#xff0c;基本上都分配了内网地址&#xff0c;现在需要这些虚拟机访问外网&#xff0c;或者外网直接访问这些虚拟机&#xff0c;必须配置一个网关服务器。我决定直接使用 Windows 的远程访问中的 NAT 服务来完成。 …

【Vue】div标签实现输入框,利用contenteditable=“true“属性的标签实现

推荐个链接&#x1f517;&#xff0c;可以更好的查阅自己遇到的问题&#xff08;点击此处即可跳转&#xff09; 使用 div 实现 input、textarea 输入框 <template><div class"content"><div class"main editTextList" ><divclass&q…

ChatGPT如何帮助学生学习

​ 一些教育工作者担心学生可能使用ChatGPT作弊。因为这个AI工具能写报告和计算机代码&#xff0c;画出复杂图表……甚至已经有许多学校把ChatGPT屏蔽。 研究发现&#xff0c;学生作弊的主要原因是想考得好。是否作弊与作业和考试的打分方式有关&#xff0c;所以这与技术的便…

《零基础入门学习Python》第062讲:论一只爬虫的自我修养10:安装Scrapy

这节课我们来谈谈 Scrapy 说到Python爬虫&#xff0c;大牛们都会不约而同地提起Scrapy。因为Scrapy是一个为了爬取网站数据&#xff0c;提取结构性数据而编写的应用框架。可以应用在包括数据挖掘&#xff0c;信息处理或存储历史数据等一系列的程序中。 Scrapy最初是为了页面抓…

2023年发布的25个开源大型语言模型总结

大型语言模型(llm)是一种人工智能(AI)&#xff0c;在大量文本和代码数据集上进行训练。它们可以用于各种任务&#xff0c;包括生成文本、翻译语言和编写不同类型的创意内容。 今年开始&#xff0c;人们对开源LLM越来越感兴趣。这些模型是在开源许可下发布的&#xff0c;这意味…

HCIA练习2

目录 第一步 启动eNSP&#xff0c;搭建如图所示的拓扑结构 第二步 进行子网的划分 ​第三步 从第二步划分的16个网段中&#xff0c;选择14个网段进行使用 第四步 对路由器各个端口进行IP配置 第五步 对每个路由器的环回接口进行配置 第六步 对路由器进行静态路由配…

Redis 命令介绍

文章目录 Redis字符串操作命令哈希操作命令列表操作命令set集合sorted set 有序集合通用命令 在Java中操作Redis&#x1f350; ❤️ &#x1f6a9;4.1 Redis的Java客户端 &#x1f350;4.2 Spring Data Redis使用方式 ✏️环境搭建步骤1). 导入Spring Data Redis的maven坐标2).…

基于SpringBoot+Vue的“智慧食堂”系统设计与实现(源码+LW+部署文档等)

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

ARM寄存器组织

一、寄存器二、ARM寄存器三、专用寄存器四、CPSR寄存器 一、寄存器 概念 寄存器是处理器内部的存储器&#xff0c;没有地址 作用 一般用于暂时存放参与运算的数据和运算结果 分类 包括通用寄存器、专用寄存器、控制寄存器 二、ARM寄存器 注 在某个特定模式下只能使用当前模…

Mac m1 下eclipse下载及jdk环境变量配置

一、安装eclipse 1、下载eclipse Eclipse downloads - Select a mirror | The Eclipse Foundation 此版本为m1芯片适用版本 2、下载后下一步安装即可 安装成功后&#xff0c;可以看到图标&#xff1a; 二、安装jdk 1、下载jdk 下载此版本即可&#xff0c;下载完成之后一直…

Django模型将模型注释同步到数据库

1、安装django-comment-migrate库 pip install django-comment-migrate 2、将库注册到settings.py文件中 INSTALLED_APPS [...django_comment_migrate, # 表注释... ] 3、加注释 3.1、给模型&#xff08;表&#xff09;加注释 在模型的class Meta中编辑 verbose_name&…

Spring Cloud+Spring Boot+Mybatis+uniapp+前后端分离实现知识付费平台免费搭建

Java版知识付费-轻松拥有知识付费平台 多种直播形式&#xff0c;全面满足直播场景需求 公开课、小班课、独立直播间等类型&#xff0c;满足讲师个性化直播场景需求&#xff1b;低延迟、双向视频&#xff0c;亲密互动&#xff0c;无论是互动、答疑&#xff0c;还是打赏、带货、…

【Postman】Newman安装与环境配置完整版(内含安装过程中遇到的问题与解决方案)

文章目录 概要Newman安装三步走一、nodejs安装与环境配置1、安装2、环境配置 二、安装newman1、步骤2、问题与解决方案 三、安装newman-reporter-html 概要 Newman&#xff1a;一款基于nodejs开发的可以运行Postman脚本的工具&#xff0c;并且可以生成测试报告。本文介绍了New…

【docker】docker部署mysql

目录 一、步骤二、说明三、示例 一、步骤 1.搜索mysql镜像 2.拉取mysql镜像 3.创建容器 4.操作容器中的mysql 二、说明 1.容器内的网络服务和外部机器不能直接通信 2.容器中部署的mysql端口3306不能被外部机器和宿主机直接通信 3.外部机器和宿主机之间可以直接通信 4.宿主机和…

管理类联考——数学——趣味篇——可视化

Manim: 一个数学可视化的动画引擎 官网&#xff1a;https://3b1b.github.io/manim/index.html 名词解析 python3.7是python语言的解释器, 运行python程序的环境必备品. 这个没啥说的,大家都能懂. 虽然官方建议3.7,但是我用3.8发现也没问题.考虑未来的历史进程,大伙最好还是装…

力扣题库刷题笔记75--颜色分类

1、题目如下&#xff1a; 2、个人Pyhon代码实现如下&#xff1a; 第一种思路是取巧&#xff0c;通过计数0、1、2的个数&#xff0c;去替换nums 备注第10行代码在本地可以跑过&#xff0c;但是力扣跑不过&#xff0c;所以就用了第10-16行代码进行替换 第二种思路是通过冒泡排序去…

小程序创建

1&#xff0c;下载HBuilder X ;(3.8.7) HBuilderX-高效极客技巧 2,下载模板&#xff08;不选云服务的&#xff09;&#xff1b; 3&#xff0c;运行-运行到小程序模拟器&#xff1b; 4&#xff0c;安装小程序开发工具&#xff1b; 5&#xff0c;选择稳定版-windows64版&…