【线程安全问题的原因和方法】【java形式】【图片详解】

news2025/3/28 19:34:36

在本章节中采用实例+图片的方式,以一个学习者的姿态进行描述问题+解决问题,更加清晰明了,以及过程中会发问的问题都会一一进行呈现

目录

  • 线程安全
      • 演示线程不安全情况
        • 图片解释:
      • 将上述代码进行修改【从并行转化成穿行的方式】
      • 不会出现问题的可能
      • 埋坑问题
    • 总结(线程安全问题产生原因)
  • 如何解决线程安全问题
    • 1.根本原因:
    • 2.多线程同时修改一个变量
    • 3.修改操作,不是原子的
    • 注意:

线程安全

概念:一段代码在多线程并发执行的情况下,出现bug的情况(实际结果与预期结果不符合),预期结果:一般是由别人来预期,此时这种情况是“线程不安全”

演示线程不安全情况

eg:(如果我们需要计算一个20000;两个线程每个线程执行10000次看其的一个情况)

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

        Thread.sleep(1000);
        System.out.println(count);
    }
}

最终运行的结果为:
在这里插入图片描述

对代码进行解释:
其中
Thread t1 = new Thread(()->{
for (int i = 0; i < 10000; i++) {
count++;
}
});
对应的是3个cpu的操作:

  1. load:将内存中的count加载到寄存器上
  2. add:把寄存器中的内容进行+1;
  3. save:把寄存器当中的内容保留在内存上

所以最终会出现这样的情况

图片解释:

对上述代码的图片解释
请添加图片描述

将上述代码进行修改【从并行转化成穿行的方式】

//只需要使用join方法就可以将并行执行的方式改为串行的方式
public class Test {
    public static int count = 0;
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(()->{
            for (int i = 0; i < 10000; i++) {
                count++;
            }
        });
        Thread t2 = new Thread(()->{
            for (int i = 0; i < 10000; i++) {
                count++;
            }
        });
        t1.start();
        t1.join();
        t2.start();
        t2.join();

        Thread.sleep(1000);
        System.out.println(count);
    }
}

最终的结果为:20000
此时上述的反应就被称为——“线程不安全”

不会出现问题的可能

  1. 如果线程重复的次数少:其运行的速度非常快,会出现一个线程执行完了,另一个线程还没有开始执行——结果就是正确的
    eg:
public class Test {
    public static int count = 0;
    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(()->{
            for (int i = 0; i < 10; i++) {
                count++;
            }
        });
        Thread t2 = new Thread(()->{
            for (int i = 0; i < 10; i++) {
                count++;
            }
        });
        t1.start();
        //t1.join();
        t2.start();
        //t2.join();

        Thread.sleep(1000);
        System.out.println(count);
    }
}

此时的结果就是正确的;
由于他的速度非常快,在状态转化的过程当中前一个线程就已经完成了操作

埋坑问题

  1. 在上述的代码当中是否可能出现最终打印的结果<5000
    答:可能会出现
    解释图片:
    请添加图片描述
    在上面的情况中会出现最终打印的1
  2. 那由上面问题 ,是否最终在我们之前写的代码中出现打印1的情况
    答:这个是不太可能的
    因为执行的次序是抢占资源的方式,在这个过程中,很少可能会出现4999都只由一个线程执行,然后由两一个线程进行收尾

总结(线程安全问题产生原因)

  1. 根本原因:操作系统对线程的调度是随机的,抢占式执行的方式
  2. 多个线程同时修改同一个变量
    以下是不会出现问题的情况:
    一个线程修改一个变量
    多个线程不同时修改同一个变量
    多个线程修改不同变量
    多个线程读取同一变量
  3. 修改操作不是原子的

进行解释:如果修改操作只对应一个cpu质量——此时原子的(例如没有多线程的时候,java当中的main线程就不会发生任何的问题)

如何解决线程安全问题

将他产生的原因尽行打破

1.根本原因:

这个是操作系统底层的设定,不能进行改变
或者自己写一个操作系统:两大难点1》技术上会非常难2》推广上会更加难

2.多线程同时修改一个变量

解决方法:调整代码结构【但是这种方法并不是通用的】

3.修改操作,不是原子的

这个是java当中解决线程安全问题,最主要的解决方案
加锁

关键字:synchronized
synchronized(加锁对象){——加锁操作
执行相关代码
}——解锁操作

加锁操作,不是将整个线程锁死在cpu上,禁止这个线程被其他的调度走,但是禁止其他线程重新加这个锁,避免其线程成的操作

java当中可以使用这个关键字修饰任何对象
只有两个线程针对同一个对象加锁操作,才会产生互斥效果

锁对象并不会影响这个对象其他方面的使用
结果展示:

public class Test2 {
    public static int count = 0;
    public static void main(String[] args) throws InterruptedException {
        Object o = new Object();
        Thread t1 = new Thread(()->{
            synchronized (o) {
                for (int i = 0; i < 10; i++) {
                    count++;
                }
            }
        });
        Thread t2 = new Thread(()->{
            synchronized (o) {
                for (int i = 0; i < 10; i++) {
                    count++;
                }
            }
        });
        t1.start();
        //t1.join();
        t2.start();
        //t2.join();

        Thread.sleep(1000);
        System.out.println(count);
    }
}

上述代码的最终的结果就可以被正确打印
对代码进行的解释:
请添加图片描述

注意:

在此过程中,只有针对同一个对象加锁才会有效果
在一般情况下:synchronized是对this进行加锁
当synchronized修饰static修饰的变量时,相当于针对类对象尽心的加锁操作

下一张会讲到死锁的问题,不要走开哦!!!!

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

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

相关文章

解决IDEA中maven找不到依赖项的问题

直接去官网找到对应的依赖项jar包&#xff0c;并且下载到本地&#xff0c;然后安装到本地厂库中。 Maven官网&#xff1a;https://mvnrepository.com/ 一、使用mvn install:install-file命令 Maven提供了install:install-file插件&#xff0c;用于手动将jar包安装到本地仓库…

pyside6的QGraphicsView体系,当鼠标位于不同的物体,显示不同的右键菜单

代码&#xff1a; # 设置样本图片的QGraphicsView模型 from PySide6.QtCore import Qt, QRectF, QObject from PySide6.QtGui import QPainter, QPen, QColor, QAction, QMouseEvent from PySide6.QtWidgets import QGraphicsView, QGraphicsScene, QGraphicsPixmapItem, QGra…

Python自动化测试 之 DrissionPage 的下载、安装、基本使用详解

Python自动化测试 之 DrissionPage 使用详解 &#x1f3e1;前言&#xff1a;一、☀️DrissionPage的基本概述二、 &#x1f5fa;️环境安装2.1 ✅️️运行环境2.2 ✅️️一键安装 三、&#x1f5fa;️快速入门3.1 页面类&#x1f6f0;️ChromiumPage&#x1f6eb; SessionPage&…

Java替换jar包中class文件

在更新java应用版本的运维工作中&#xff0c;由于一些原因&#xff0c;开发没办法给到完整的jar包&#xff0c;这个时候&#xff0c;就可以只将修改后的某个Java类的class文件替换掉原来iar包中的class文件&#xff0c;重新启动服务即可&#xff1a; 1、将jar包和将要替换的cl…

AI Tokenization

AI Tokenization 人工智能分词初步了解 类似现在这个&#xff0c;一格子 一格子&#xff0c;拼接出来的&#xff0c;一行或者一句&#xff0c;像不像&#xff0c;我们人类思考的时候组装出来的话&#xff0c;并用嘴说出来了呢。

关于大数据的基础知识(四)——大数据的意义与趋势

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///计算机爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于大数据的基础知识&#xff08;四&a…

某视频的解密下载

下面讲一下怎么爬取视频&#xff0c;这个还是比小白的稍微有一点绕的 首先打开网址&#xff1a;aHR0cDovL3d3dy5wZWFydmlkZW8uY29tL3BvcHVsYXJfNA 首页 看一下&#xff1a; 有一个标题和一个href&#xff0c;href只是一个片段&#xff0c;待会肯定要拼接&#xff0c; 先找一…

Day20-前端Web案例——部门管理

目录 部门管理1. 前后端分离开发2. 准备工作2.1 创建Vue项目2.2 安装依赖2.3 精简项目 3. 页面布局3.1 介绍3.2 整体布局3.3 左侧菜单 4. Vue Router4.1 介绍4.2 入门4.3 案例4.4 首页制作 5. 部门管理5.1部门列表5.1.1. 基本布局5.1.2 加载数据5.1.3 程序优化 5.2 新增部门5.3…

从切图仔到鸿蒙开发01-文本样式

从切图仔到鸿蒙开发01-文本样式 本系列教程适合 HarmonyOS 初学者&#xff0c;为那些熟悉用 HTML 与 CSS 语法的 Web 前端开发者准备的。 本系列教程会将 HTML/CSS 代码片段替换为等价的 HarmonyOS/ArkUI 代码。 页面结构 HTML 与 ArkUI 在 Web 开发中&#xff0c;HTML 文档结…

菱形虚拟继承的原理

一 &#xff1a;菱形继承的问题 普通的菱形继承存在数据冗余和二义性的问题 &#xff0c;如下代码&#xff1a; class Person { public:string _name; //姓名 };class Student : public Person { protected:int _num; //学号 };class Teacher : public Person { protected:int…

【数据结构】C语言实现树和森林的遍历

C语言实现树和森林的遍历 导读一、树的遍历二、森林的遍历2.1 为什么森林没有后序遍历?2.2 森林中存不存在层序遍历?三、C语言实现3.1 准备工作3.2 数据结构的选择3.3 树与森林的创建3.4 树与森林的遍历3.4.1 先根遍历3.4.2 后根遍历3.4.3 森林的遍历3.5 树与森林的销毁3.6 算…

第四天 开始Unity Shader的学习之旅之Unity中的基础光照

Unity Shader的学习笔记 第四天 开始Unity Shader的学习之旅之Unity中的基础光照 文章目录 Unity Shader的学习笔记前言一、我们是如何看到这个世界的1. 光源2.吸收和散射3.着色 二、标准光照模型1. 自发光2. 高光反射① Phong模型② Blinn-Phong模型 3.漫反射4.环境光 总结 前…

基于SpringBoot的“社区居民诊疗健康管理系统”的设计与实现(源码+数据库+文档+PPT)

基于SpringBoot的“社区居民诊疗健康管理系统”的设计与实现&#xff08;源码数据库文档PPT) 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 系统模块功能结构图 局部E-R图 系统首…

Java-空链基础入门

经过调研和细致观察&#xff0c;我们发现空链对于初次接触或是对Stream和Optional不太熟悉的人来说&#xff0c;确实存在一定的上手难度&#xff0c;宛如开启了“地狱模式”。为了降低这一门槛&#xff0c;我们决定通过一系列由简入深的案例演示&#xff0c;来逐步引导大家掌握…

【江协科技STM32】Unix时间戳BKP备份寄存器RTC实时时钟(学习笔记)

Unix时间戳 Unix 时间戳&#xff08;Unix Timestamp&#xff09;定义为从UTC/GMT的1970年1月1日0时0分0秒开始所经过的秒数&#xff0c;不考虑闰秒时间戳存储在一个秒计数器中&#xff0c;秒计数器为32位/64位的整型变量世界上所有时区的秒计数器相同&#xff0c;不同时区通过…

3.17-3.23 Web3 游戏周报:Pixudi 双榜领跑,The Forgotten Runiverse 登陆三大主机平台

回顾上周的区块链游戏概况&#xff0c;查看 Footprint Analytics 与 ABGA 最新发布的数据报告。 【3.17–3.23】Web3 游戏行业动态 Ronin 将与 Alpha Growth 等合作推出 1300 万美元增长计划&#xff0c;以向 DeFi 扩张Notcoin 开发工作室 Open Builders 宣布推出 Not Games …

AppInventor2生成3位数的水仙花数

生成3位水仙花数&#xff08;每位数字的立方之和刚好等于这个数字&#xff09;的代码&#xff0c;如下&#xff1a; 来源&#xff1a;【生成Python】AppInventor2中文网已支持代码块转换Python源码&#xff01; - App Inventor 2 中文网 - 清泛IT社区&#xff0c;为创新赋能&…

【聚类算法解析系列02】经典聚类算法(上)——K-Means与层次聚类

【聚类算法解析系列02】经典聚类算法&#xff08;上&#xff09;——K-Means与层次聚类 引言&#xff1a;算法背后的认知革命 K-Means与层次聚类&#xff0c;这两个诞生于1960年代的算法&#xff0c;至今仍是工业界使用率最高的聚类工具。它们分别代表了两种根本性的世界观&am…

[Effective C++]条款22:将成员变量声明为private

. 在C中&#xff0c;将成员变量声明为private而不是public&#xff0c;主要是为了遵循面向对象编程&#xff08;OOP&#xff09;的封装原则。他有助于隐藏对象的内部实现细节&#xff0c;提供更好地控制&#xff0c;安全性和可维护性。 1、数据隐藏与封装 将成员变量声明为pr…

心法利器[132] | 大模型系统性能优化trick

心法利器 本栏目主要和大家一起讨论近期自己学习的心得和体会。具体介绍&#xff1a;仓颉专项&#xff1a;飞机大炮我都会&#xff0c;利器心法我还有。 2023年新的文章合集已经发布&#xff0c;获取方式看这里&#xff1a;又添十万字-CS的陋室2023年文章合集来袭&#xff0c;更…