操作系统_线程安全问题

news2024/11/26 20:28:58

文章目录

  • 1.线程安全问题举例
  • 2.为什么会有线程安全问题
  • 3.如何解决线程安全问题
    • 1.从原子性入手解决线程安全问题
    • 2.synchronized的使用方法
    • 3.java标准库中的线程安全类
  • 4.死锁问题
    • 举例
    • 2.死锁的必要条件

1.线程安全问题举例

看代码:

class Count {
    int i = 0;
    public void add(){
        i++;
    }
}
public class Test1 {
    public static void main(String[] args) throws InterruptedException {
        Count count = new Count();
        
        //创建一个线程,使i自加1w次
        Thread thread1 = new Thread(() ->{
            for (int i = 0; i < 10000; i++) {
                count.add();
            }
        });

        //再次创建一个线程,使i自加1w次
        Thread thread2 = new Thread(() -> {
            for (int i = 0; i < 10000; i++) {
                count.add();

            }
        });
        
        thread1.start();
        thread2.start();
        thread1.join();
        thread2.join();
        
        System.out.println(count.i);//打印i自加2w次之后的结果

    }
}

结果:
在这里插入图片描述
在这里插入图片描述

i自加2w次之后应该是2w,可是第一次打印的结果是18971,第二次打印的结果是19478,与我们想象的2w有一定的差距,上面这种情况就叫是典型的线程安全问题.


为什么会出现这种情况?
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
还有无数种情况就不一 一列举了;其中只有第一次情况是正确的

  1. 由于线程的抢占式执行,导致当前线程执行到任意一个指令的时候,都有可能被调度走,CPU让别的线程来执行;
  2. CPU里有个重要的组成部分,寄存器.寄存器也能存数据.空间更小,访问速度更快.CPU进行的运算都是针对寄存器中的数据进行的.

在这里插入图片描述

2.为什么会有线程安全问题

因为线程的抢占式执行模式,导致代码执行的顺序会有很多变数,代码的执行顺序就从一种情况变成了无数种情况,所以就需要保证在这种有无数种想成调度顺序的情况下,代码执行结果是正确的
问题一: 能否消除线程执行顺序的随机性?
不能!


出现线程安全问题的原因:
在这里插入图片描述
这五个只是典型的线程安全问题的原因,并不是全部原因

3.如何解决线程安全问题

1.从原子性入手解决线程安全问题

关键字:synchronized
class Count {
    int i = 0;
    synchronized public void add(){
        i++;
    }
}

当我们给上面的方法加上synchronized之后,进入方法就加锁,出了方法就会解锁,如果两个线程同时尝试加锁,那么只有一个线程可以成功,另外一个线程只能阻塞等待(BLOCKED),直到刚才加锁成功的线程解锁,当前阻塞等待的线程才能加锁成功!!!
在这里插入图片描述

2.synchronized的使用方法

在这里插入图片描述
注意:

  1. 一个线程可以给两个对象加锁
  2. 线程是对对象加锁,虽然synchronized是修饰在方法上的
  3. 在这里插入图片描述

在这里插入图片描述
注意:synchronized是可重入的,因为对于同一个锁对像(this)第一次进入的时候对他加锁了,第二次再进入的时候,就会发现已经上过锁了,此时是不会进入线程阻塞的,因为第一个线程和第二个线程是同一个线程

3.java标准库中的线程安全类

在这里插入图片描述

4.死锁问题

举例

为什么会有死锁问题?
1.一个线程一把锁,连续加锁两次,如果锁是可重入锁,就没有问题(java中的synchronized和ReentrantLock就是可重入锁),如果所示不可重入锁,就会出现死锁问题;
在这里插入图片描述
2.两个线程两把锁,t1和t2都各自针对锁A和锁B加锁,接着又尝试获取对方的锁

class B{

}
public class Test3 {
    public static void main(String[] args) throws InterruptedException {
        B chifan = new B();
        B heshui = new B();
        Thread t1 = new Thread(() -> {
           synchronized (chifan){ 
               System.out.println("小明 -> 吃饭");
               synchronized (heshui){
                   System.out.println("小明 -> 吃饭、喝水");
               }
           }

        });
        Thread t2 = new Thread(() -> {
           synchronized (heshui){
               System.out.println("小红 -> 喝水");
               synchronized (chifan){
                   System.out.println("小红 -> 喝水、吃饭");
               }
           }

        });
        t1.start();

        t2.start();
    }

}

结果;
在这里插入图片描述

为什么会有上面的情况出现呢?
因为t1线程对chifan这个对象加锁之后,t2同时也对heshui这个对象加锁,二者并没有释放锁的时候,又想要去获取对方并没有释放的锁,这是不可能实现的!

但是我们稍微调整一下代码就可以解决这个问题:

在这里插入图片描述

2.死锁的必要条件

  1. 互斥使用:线程1拿到了锁,线程2就要等待;
  2. 不可抢占:线程1拿到了锁之后,必须是线程1主动释放,不能是线程2强行获取锁;
  3. 请求和保持:线程1获取锁A之后,再去获取锁B,A锁还是保持的(并不会因为线程1又获取了锁B就把锁A释放了);
  4. 循环等待:线程1尝试获取锁A和锁B,线程2尝试获取锁B和锁A,线程1获取B的时候等待线程2释放B,线程2获取A的时候等待线程1释放锁A;

前三点都是固定好的,只有第四点使我们自己可以控制的。
如何突破死锁是一个比较复杂的问题!后面会详细讲解。

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

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

相关文章

Sklearn机器学习与Plotly可视化强强联合

在学习sklearn(机器学习)过程中&#xff0c;模型原理可谓是枯燥无味&#xff0c;加上大多数模型训练过程也是不可见的&#xff0c;这使得很多小伙伴们望而却步&#xff0c;当然也有很多学者试图通过各种方式以可视化模型学习及预测过程&#xff0c;但大多数是复杂且不美观的。 …

Windows后台运行并启动Frpc客户端界面

Windows后台运行并启动Frpc客户端界面 frp搭建内网穿透可以看我另外一篇 1.frps服务端配置 [common] bind_port 3000 vhost_http_port 4000 vhost_https_port 5000authentication_method token authenticate_new_work_conns true token 5ae9394f-32d8-4a58-b6ed-e9f36…

【微服务技术05】Ribbon负载均衡

【微服务技术05】Ribbon负载均衡 案例代码&#xff1a;https://gitee.com/pikachu2333/spring-cloud-hexuan 之前配置好了eureka注册中心&#xff0c;使用RestTemplate调用地址为&#xff1a;http://eureka-user-service/user/1&#xff0c;配置了LoadBalanced负载均衡注解 但…

使用RTP包荷载AAC码流数据

目录 一. 前言 二. RTP协议介绍 三. AAC介绍 1. AAC格式 2. ADTS 四. RTP与AAC的结合 五. 代码实战 六. 效果展示 一. 前言 音视频通话中我们通常使用 RTP 协议包荷载音视频码率数据&#xff0c;例如麦克风采集输入数据后编码成帧&#xff0c;再将帧数据放入 RTP 协议包…

B站:以SLO为核心的可用性观测与质量运营

UGeek大咖说是优维科技为技术爱好者研讨云原生技术演进趋势而创办的系列活动&#xff0c;邀请一线互联网大厂的核心骨干主讲&#xff0c;分享原厂实践。本年度主题为可观测&#xff0c;我们希望通过一场场有趣、有料、有深度的活动&#xff0c;让运维圈的小伙伴聚集在一起&…

Java知识点--反射(上)

Java知识点--反射&#xff08;上&#xff09;&#x1f356;一、为什么需要反射1️⃣在特定情境中传统方法的不足2️⃣为了不修改原码引出反射&#x1f357;二、反射机制1️⃣Java反射机制2️⃣Java 反射机制原理示意图3️⃣Java 反射机制可以完成4️⃣反射相关的主要类5️⃣反射…

java计算机毕业设计ssm在线学习资源管理系统t4ko5(附源码、数据库)

java计算机毕业设计ssm在线学习资源管理系统t4ko5&#xff08;附源码、数据库&#xff09; 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#…

2023最新SSM计算机毕业设计选题大全(附源码+LW)之java丹徒高级中学校车预约9poqj

大四计算机专业的同学们即将面临大学4年的最后一次考验--毕业设计。通过完成毕业设计来对过去4年的大学学习生活做一个总结&#xff0c;也是检验我们学习成果的一种方式&#xff0c;毕业设计作品也是我们将来面试找工作的一个敲门砖。 选题前先看看自己掌握哪些技术点、擅长哪…

Denoising Diffusion Probabilistic Models

目录概要前向过程nice property逆向过程参数推导简化参考资料概要 Denoising Diffusion Probabilistic Model(DDPM)是一个生成模型&#xff0c;给定一个目标分布&#xff0c;学习模型以便可以从目标分布中采样。 使用马尔科夫链建模。输入是噪声&#xff0c;通过神经网络逐步去…

伟大的缝纫师—typedef

伟大的缝纫师—typedef一.历史的误会—也许应该是typerename二.typedef和#define的区别一.历史的误会—也许应该是typerename 为什么这样说呢&#xff1f;因为typedf其实就是一个重命名关键字&#xff0c;看示例 这里我觉得unsigned int太长了&#xff0c;我将它改名为u_int&am…

bat批处理文件的注释,和常用简单命令

参考&#xff1a;https://learn.microsoft.com/zh-cn/windows-server/administration/windows-commands/windows-commands&#xff0c;https://blog.csdn.net/wuhenyouyuyouyu/article/details/120736519? 当前路径&#xff1a;%~dp0 这个参数只能在bat文件中在正常使用&…

Unity脚本(2) --- 脚本生命周期以及脚本的控制台调试

1.什么是脚本生命周期&#xff1f; 首先什么是脚本 --- 脚本的本质其实就是类&#xff0c;而脚本生命周期其实就是脚本对应的那个类从开始工作到最后销毁这么一个周期 &#xff08;或者说是Unity脚本从唤醒到销毁的过程&#xff09; &#xff08;消息&#xff0c;必然事件&am…

[附源码]Node.js计算机毕业设计儿童成长记录与分享系统Express

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…

【Vue实践】尚硅谷张天禹Vue学习笔记(更新至第86课)-20221126~20221212

004_尚硅谷Vue技术_搭建Vue开发环境 搭建Vue.js devtools 允许访问文件网址 https://blog.csdn.net/sunhl951/article/details/80185628 阻止 vue 在启动时生成生产提示。 Vue.config.productionTip false 目测没有用 https://blog.csdn.net/DIUDIUjiang/article/details/…

这些车企在企业微信里,装上高速的“组织引擎”

“这真是一场惊险之旅。” 今年7月&#xff0c;胡先生一家疾驶在若羌县罗布泊镇国道上&#xff0c;迎面突然冲出一辆大型货车……为了避让&#xff0c;胡太太驾驶的极氪001撞上了路边的石墩&#xff0c;两个轮胎直接报废。 在人迹罕至的无人区&#xff0c;保险公司鞭长莫及&a…

C++ 基础篇之如何进行数据封装

&#x1f4d2;博客主页&#xff1a; ​​开心档博客主页​​ &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐留言&#x1f4dd; &#x1f4cc;本文由开心档原创&#xff01; &#x1f4c6;51CTO首发时间&#xff1a;&#x1f334;2022年12月12日&#x1f334; ✉…

rocketmq源码-producer启动流程

前言 DefaultMQProducer producer new DefaultMQProducer("please_rename_unique_group_name"); producer.setNamesrvAddr("127.0.0.1:9876");producer.setNamesrvAddr("127.0.0.1:9876");producer.start();创建、启动producer的逻辑&#xff…

[附源码]Node.js计算机毕业设计电影推荐网站Express

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…

对长尾识别任务中解耦方法的改进

来源&#xff1a;投稿 作者&#xff1a;TransforMe 编辑&#xff1a;学姐 贡献 在长尾识别任务上&#xff0c;解耦&#xff08;二阶段&#xff09;的方法取得了巨大的进步&#xff0c;详情参考https://blog.csdn.net/weixin_41246832/article/details/115718084。本文详细分析…

Android实现SSH Client

本文实现的是如何使用JSCH在Android上实现一个简易版本的ssh client&#xff0c;来远程执行ssh命令。 1、启动ssh服务&#xff0c;本文以mac为例。 打开设置-->共享-->选择远程登录 2、检验ssh server是否开启成功。 打开shell ssh dongxuliip 输入dongxuli账户的密码&…