Java:线程安全

news2025/1/16 14:41:12

引子

首先来看一段代码:

    private static int count = 0;
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(()->{
            for (int i = 0; i < 50000; i++) {
                count++;
            }
        });
        Thread t2 = new Thread(()->{
            for (int i = 0; i < 50000; i++) {
                count++;
            }
        });

        t1.start();
        t2.start();
        
        t1.join();
        t2.join();

        System.out.println(count);
    }

运行结果:
第一次
在这里插入图片描述
第二次
在这里插入图片描述
第三次
在这里插入图片描述
我们发现,以上代码有bug,我们的预期是10w,显然上述的结果不是我们想要的.

初次分析

为什么会出现上述的问题呢?
我们来分析一下.
如果我们把代码修改成这样:

	t1.start();
    t1.join();
        
    t2.start();
    t2.join();

运行结果就没问题了.
这个写法本质上相当于,t1先执行,t1执行完了,t2再执行,此时t1和t2是串行执行的.

而刚刚的代码:

	t1.start();
    t2.start();
        
    t1.join();
    t2.join();

这个写法,t1和t2是并发执行的.

由此我们可以知道这是由于多个线程并发执行引起的bug.
这样的bug就称为"线程安全问题"或者叫做"线程不安全".

再次分析

那这个bug到底是怎么出现的呢,换句话说,为什么会出现线程不安全呢?
线程不安全是一个综合性的问题.竖起耳朵仔细听啦~

代码中的 count++; 操作,其实在CPU视角来看,是3个指令:

  1. 把内存中的数据读取到CPU寄存器里
  2. 把CPU寄存器里的数据 +1
  3. 把寄存器的值,写回内存
    为了方便叙述,给上面三步分别起名为 load , add , save.
    (由于不同架构的CPU有不同的指令集,所以对于这三个操作,不同的CPU里对应指令的名称肯定是不同的~)

由于CPU是"抢占式执行,随机调度"的,也就是说CPU在调度执行线程的时候,不定啥时候就会把线程给切换走.
(指令是CPU执行的最基本单位,它不会执行一半就被调走)

但是由于count++ 是三个指令,可能会出现CPU执行了其中的1个指令或者两个指令或者三个指令就被调度走的情况(无法预测).

基于上面的情况,两个线程同时对count进行++,就容易出现bug
正常情况如下
在这里插入图片描述
上述的执行顺序,只是一种可能的调度顺序.由于调度过程是"随机"的,因此就会产生很多其他的执行顺序~

比如:

在这里插入图片描述

甚至:

在这里插入图片描述
相信你看完下面的图,肯定就会理解了~
在这里插入图片描述
通过上述分析,我们发现对于多线程代码来说,最大的困难就在于线程在操作系统中是"随机调度,抢占式执行"的,这简直就是"罪魁祸首,万恶之源"啊.


总结

最后总结一下为什么最开始的代码有bug吧:

  1. 线程在操作系统中是"随机调度,抢占式执行"的
  2. 多个线程,同时修改了同一个变量
  3. 修改操作,不是"原子的"

怎么规避呢?
第一条原因我们一般不能改,但是我们可以改第二条,比如说改成使用一个线程,或者使用多个线程修改不同的变量等等.

我们写多线程代码需要在所有可能的线程调度的顺序下,确保每一种情况都没有bug.这也是多线程代码最困难也最复杂的地方,学习这一块时要有心里预期啊~

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

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

相关文章

Java语言程序设计——篇十一(4)

&#x1f33f;&#x1f33f;&#x1f33f;跟随博主脚步&#xff0c;从这里开始→博主主页&#x1f33f;&#x1f33f;&#x1f33f; 欢迎大家&#xff1a;这里是我的学习笔记、总结知识的地方&#xff0c;喜欢的话请三连&#xff0c;有问题可以私信&#x1f333;&#x1f333;&…

深入解析 KMZ 文件的处理与可视化:从数据提取到地图展示项目实战

文章目录 1. KMZ 文件与 KML 文件简介1.1 KMZ 文件1.2 KML 文件 2. Python 环境配置与依赖安装3. 代码实现详解3.1 查找 KMZ 文件3.2 解压 KMZ 文件3.3 解析 KML 文件3.4 可视化 KMZ 数据 4. 项目实战4.1. 数据采集4.2. 项目完整代码 5. 项目运行与结果展示6. 总结与展望 在处理…

2007-2023年上市公司国内外专利申请获得情况数据

2007-2023年上市公司国内外专利申请获得情况数据 1、时间&#xff1a;2007-2023年 2、来源&#xff1a;上市公司年报 3、指标&#xff1a;证券代码、统计截止日期、报表类型、地区、申请类型编码、申请类型、专利&#xff08;件&#xff09;、发明专利&#xff08;件&#x…

动态路由协议基础

一、动态路由协议简介 动态路由协议:路由器用来计算和维护路由信息的协议;通俗的说,就算路由器用来学习路由的协议。 二、动态路由与静态路由的区别 静态路由动态路由路由表手工配置自动生成路由维护人工维护自动收敛资源消耗路由表生成不占网络资源路哟表生成占用网络资源…

学习Java的日子 Day59 学生管理系统 web1.0版本

Day59 学生管理系统 web1.0 1.项目需求 有两个角色&#xff0c;老师和学生&#xff0c;相同的功能提取到父类用户角色 2.数据库搭建 设计学生表 设计老师表 插入数据 (超级管理员) 设计学科表 3.项目搭建 处理基础页面&#xff0c;分包&#xff0c;实体类&#xff0c;导入数据…

微软AI业务最新营收数据情况(2024年7月)

Azure AI 年度经常性收入 (ARR)&#xff1a;达到50亿美元客户数量&#xff1a;60,000家平均客户价值 (ACV) 中位数&#xff1a;83,000美元同比增长率&#xff1a;达到了惊人的900% GitHub Copilot 年度经常性收入 (ARR)&#xff1a;达到3亿美元客户数量&#xff1a;77,000家…

每日两题8

买卖股票的最佳时机 III class Solution { public:int maxProfit(vector<int>& prices) {int n prices.size();int INF 0x3f3f3f3f;vector<vector<int>> f(n, vector<int>(3, -INF));auto g f;g[0][0] 0;f[0][0] -prices[0];for (int i 1; i…

Leetcode3227. 字符串元音游戏

Every day a Leetcode 题目来源&#xff1a;3227. 字符串元音游戏 解法1&#xff1a;博弈论 分类讨论&#xff1a; 如果 s 不包含任何元音&#xff0c;小红输。如果 s 包含奇数个元音&#xff0c;小红可以直接把整个 s 移除&#xff0c;小红赢。如果 s 包含正偶数个元音&am…

10.Redis类型SortedSet

介绍 Redis的SortedSet是一个可排序的set集合。与java的TreeSet有些类似&#xff0c;但底层数据结构却差别很大。 SortedSet中的每个元素都带有一个score属性&#xff0c;可以基于score属性对元素排序&#xff0c;底层实现是一个跳表SkipList加hash表。 特点 可排序 元素不…

“银狐”团伙再度出击:利用易语言远控木马实施钓鱼攻击

PART ONE 概述 自2023年上半年“银狐”工具被披露以来&#xff0c;涌现了多个使用该工具的黑产团伙。这些团伙主要针对国内的金融、教育、医疗、高新技术等企事业单位&#xff0c;集中向管理、财务、销售等从业人员发起攻击&#xff0c;窃取目标资金和隐私信息。该团伙惯用微信…

多旋翼+四光吊舱:5Kg负载无人机技术详解

多旋翼无人机是一种具有三个及以上旋翼轴的无人驾驶飞行器。它通过每个轴上的电动机转动&#xff0c;带动旋翼&#xff0c;从而产生升推力。旋翼的总距固定&#xff0c;不像一般直升机那样可变。通过改变不同旋翼之间的相对转速&#xff0c;可以控制飞行器的运行轨迹。多旋翼无…

Js在线Eval加密混淆及解密运行

具体请前往&#xff1a;Js在线Eval加密混淆及解密运行

自动打电话软件的效果怎么样?

​​使用这个系统&#xff0c;机器人自动拨打电话&#xff0c;真人录制的语音与客户对话&#xff0c;整个过程非常顺畅。而且系统可以每天外呼数千乃至数万通电话&#xff0c;是人工的5-10倍&#xff0c;这样就不需要招聘大量员工来外呼&#xff0c;只需要留下一些优秀的销售人…

动视封禁超过6.5万名《战区》和《MW3》作弊者

动视已经在《使命召唤&#xff1a;战区》和《使命召唤&#xff1a;现代战争3》中封禁了超过65000名玩家。这些封禁在过去的几小时内实施&#xff0c;清除了数千名在排名赛和非排名赛中“作弊和代练”的玩家。 Ricochet反作弊团队现已清理了《使命召唤&#xff1a;战地》和《现代…

【PyTorch】神经风格迁移项目

神经风格迁移中&#xff0c;取一个内容图像和一个风格图像&#xff0c;综合内容图像的内容和风格图像的艺术风格生成新的图像。 目录 准备数据 处理数据 神经风格迁移模型 加载预训练模型 定义损失函数 定义优化器 运行模型 准备数据 创建data文件夹&#xff0c;放入…

人工智能与大数据的融合:驱动未来的力量

人工智能与大数据的融合&#xff1a;驱动未来的力量 一、人工智能与大数据的概述二、人工智能与大数据在数据库中的融合三、实际应用案例四、未来发展方向总结 【纪录片】中国数据库前世今生 在数字化潮流席卷全球的今天&#xff0c;数据库作为IT技术领域的“活化石”&#xff…

16进制转换-系统架构师(三十九)

1、&#xff08;软件架构设计->构件与中间件技术->构件标准&#xff09;对象管理组织&#xff08;OMG&#xff09;基于CORBA基础设施定义了四种构件标准。其中&#xff0c;&#xff08;&#xff09;状态信息是构件自身而不是由容器维护的。 A实体构件 B加工构件 C服务…

C++中lambda使用mutable关键字详解

C中lambda使用mutable关键字详解 在《C初学者指南-5.标准库(第二部分)–更改元素算法》中&#xff0c;讲“generate”算法时有下面这段代码&#xff1a; auto gen [i0]() mutable { i 2; return i; }; std::vector<int> v; v.resize(7,0); generate(begin(v)1, begin…

(南京观海微电子)——LCD OTP(烧录)介绍

OTP OTP只是一种存储数据的器件&#xff0c;全写:ONETIMEPROGRAM。 OTP目的&#xff1a;提高产品的一致性 客户端的接口不支持和我们自己的产品IC之间通信&#xff0c;即不支持写初始化&#xff0c;所以产品的电学功能以及光学特性需要固化在IC中&#xff0c;所以需要我们来进行…

青甘环线游记|day(1)|兰州

出发 下午1点&#xff0c;登机。航班经停万州&#xff0c;再到兰州。下图为飞机上拍的照片&#xff0c;不知道为什么窗户上有结晶的东西&#xff08;&#xff1f;&#xff09; 在飞机上拍的航线图&#xff0c;但是有点模糊。飞机上有提供午餐。4点左右到达万州 在飞机上好像…