多线程之死锁

news2025/1/13 13:56:40

目录:

1.什么是死锁?

2.可重入与不可重入

3.发生死锁的三个典型情况

4.发生死锁的四个必要条件

5.如何破除死锁?



1.什么是死锁?

谈到死锁,程序猿们都心存忌惮,因为程序一旦出现死锁,就会导致线程无法继续执行后面的工作了,那么这个程序就会出现非常大的bug。而且死锁一般来说,不易发现,在开发阶段如果写出了死锁代码,那么很可能测试是测试不出来的,所以出现死锁问题还是非常不爽的。下面将详细谈谈关于死锁。

2.可重入与不可重入

一个线程针对同一个对象连续加锁两次。如果没有出现问题就是可重入的,如果出现问题了那么就是不可重入的。

此时锁对象是this,只要有线程调用add方法,那么进入add方法的时候就会先加锁,进去之后又遇到了代码块,将再次尝试加锁。站在this(锁对象)的角度,它认为自己已经被线程占用了,这里的第二次加锁是否要阻塞等待呢?如果允许第二次加锁,那么这个锁就是可重入的;如果不允许第二次加锁,第二次加锁会发生阻塞等待,那么就是不可重入的,这个时候就发生僵持了,就发生死锁了。在java中,把synchronized设定成可重入的了。 

3.发生死锁的三个典型情况

1.一个线程针一把锁连续加锁两次。如果锁是不可重入锁,就会死锁。

2.两个线程两把锁,t1先对锁A加锁,t2先对锁B加锁,然后各自再尝试获取对方的锁,就会死锁。代码示例:

public class ThreadDemo10 {
    public static void main(String[] args) {
        Object A = new Object();
        Object B = new Object();

        Thread t1 = new Thread(()->{
            synchronized (A){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                synchronized (B){
                    System.out.println("A去拿B的锁了");
                }
            }
        });

        Thread t2 = new Thread(()->{
            synchronized (B){
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

                synchronized (A){
                    System.out.println("B去拿A的锁了");
                }
            }
        });
    }
}

运行结果如下:(出现死锁了)

用jconsole查看线程情况:

 这里很明显可以看到这两把锁互相僵持住了,出现了死锁问题。针对这样的死锁问题,也是需要借助像jconsole 这样的工具来进行定位的,看线程的状态和调用栈,就可以分析出代码是在哪里死锁了。 

3.多个线程多把锁

因为由于操作系统的随机调度,多个线程对多把锁可能会随机加锁,那么就会出现第二点那样的情况,相互僵持,出现死锁。如何解决这个问题呢?可以把锁进行编号,然后对线程进行约定,默认从编号小的开始加锁,这样就可以死锁问题。然后我们将第二点的实例代码改造一下,默认都先对A加锁,再对B进行加锁,这样就不会出现死锁了。代码示例:

Thread t1 = new Thread(()->{
    synchronized (A){
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        synchronized (B){
            System.out.println("t1把A和B都拿到了");
        }
    }
});
Thread t2 = new Thread(()->{
    synchronized (A){
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        synchronized (B){
            System.out.println("t2把A和B都拿到了");
        }
    }
});

运行结果如下:

  

4.发生死锁的四个必要条件

1.互斥使用,线程1拿到了锁,线程2就得等着。(锁的基本特性)

2.不可抢占,线程1拿到锁之后,必须是线程1主动释放,不能说是线程2就把锁给强行获取到。

3.请求和保持,线程1拿到锁A之后,再尝试获取锁B,A这把锁还是保持的。(不会因为获取锁B就把A给释放了)

4.循环等待,线程1尝试获取到锁A和锁B,线程2尝试获取到锁B和锁A。线程1在获取B的时候等待线程2释放B;同时线程2在获取A的时候等待线程1释放A

5.如何破除死锁?

在上面也已经谈到了,破除死锁的办法就是给锁编号,然后指定一个固定的顺序(比如从小到大)来加锁。任意线程加多把锁的时候,都让线程遵守上述顺序,此时循环等待就自然破除了。

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

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

相关文章

深度学习训练营之鸟类识别

深度学习训练营之鸟类识别原文链接环境介绍前置工作设置GPU导入数据并进行查找数据处理可视化数据配置数据集残差网络的介绍构建残差网络模型训练开始编译结果可视化训练样本和测试样本预测原文链接 🍨 本文为🔗365天深度学习训练营 中的学习记录博客&am…

机器学习:如何解决类别不平衡问题

类别不平衡是一个常见问题,其中数据集中示例的分布是倾斜的或有偏差的。 1. 简介 类别不平衡是机器学习中的一个常见问题,尤其是在二元分类领域。当训练数据集的类分布不均时会发生这种情况,从而导致训练模型存在潜在偏差。不平衡分类问题的示…

【Unity云消散】理论基础:实现SDF的8SSEDT算法

距离元旦假期已经过去5天了(从31号算起!),接着开始学习! 游戏中的很多渲染效果都离不开SDF,那么SDF究竟是什么呢?到底是个怎么样的技术?为什么能解决那么多问题? 1 SD…

git介绍及环境搭建

git介绍及环境搭建Git介绍Git安装流程配置用户信息git工作流程与常用命令问题点总结主要工作流程git工作流程与原理总结Git介绍 1.Git是什么? Git版本控制系统是一个分布式的系统,是用来保存工程源代码历史状态(游戏存档)的命令行工具 GIT是一个命令行工具,用于版…

基于Java+Spring+vue+element社区疫情服务平台设计和实现

基于JavaSpringvueelement社区疫情服务平台设计和实现 博主介绍:5年java开发经验,专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 文末获取源…

Django+channels -> websocket

Django+channels -> websocket 学习视频: https://www.bilibili.com/video/BV1J44y1p7NX/?p=10 workon # 查看虚拟环境 mkvirtualenv web -p python3.10 # 创建虚拟环境 workon web # 进入虚拟环境pip insatll django channelsdjango-admin startproject ws_demo python …

【NI Multisim 14.0原理图环境设置——元器件库管理】

目录 序言 一、元器件库管理 🍉1.“元器件”工具栏 🍊(1)电源/信号源库 🍊(2)基本器件库 🍊(3)二极管库 🍊(4)晶体管…

seL4 背景知识

1 seL4 演变 1.1 微内核 微内核发展到目前为止经历了三代, 这里做一些归纳。参考《现代操作系统: 原理与实现》中操作系统结构一章, 关于微内核架构发展的介绍。 第一代微内核设计将许多内核态功能放到用户态, Mach 微内核是第一代微内核的代表。第二代微内核设计将对 IPC 优…

C++学习记录——일 C++入门(1)

C入门(1) 文章目录C入门(1)一、C关键字二、C第一个程序三、命名空间1、域作用限定符2、了解命名空间3、命名空间的使用四、C输入输出五、缺省参数六、函数重载七、引用1、引用符号2、引用的部分使用场景一、C关键字 关键字有98个&…

filebeat采集nginx日志

背景我们公司项目组用的是elastic的一整套技术栈,es,kibana,filebeat和apm,目前已经可以采集网关各个微服务的日志。架构图现在需要在原来的基础上把nginx这的日志也采集上来,方便做链路跟踪问题与思路原先traceId是在…

数字经济时代,“8K+”开拓行业新格局

2023深圳国际8K超高清视频产业发展大会召开,大会以“超清互联 数智创新”为主题,汇聚两院院士、产业领袖、领军企业共同深入探讨超高清产业发展现状、关键问题和未来趋势,并集中发布《深圳市超高清视频显示产业白皮书(2023版&…

「数据密集型系统搭建」开卷篇|什么是数据密集型系统

在我们开发的诸多系统,基本都可以视为“数据密集型系统”,数据是一切物质的载体,我们依靠数据做存储记录,通过数据进行信息传递交换,最终还要数据来呈现和展示等,从一定视角而言,系统中最核心、…

临时用网搞不定?别着急,5G网络“急救车”来啦

如何在1天时间内,用不超过5名装维人员,完成超过200间宿舍的网络覆盖,让即将踏上考场的高三学子们尽快用上网络? 近期,这个问题一直困扰着重庆电信客户经理周睿。原来,由于疫情原因,重庆市某中学…

WINDOWS安装Oracle11.2.0.4

(一)Oracle服务器端安装 1.运行Oracle11g服务器端安装程序setup.exe,弹出如下界面: 2.如上界面中,把默认打上的勾去掉,然后点击【下一步】,弹出如下界面: 3.如上界面中,选择跳过软件更新,然后点击【下一步…

指针进阶(三)再谈数组与串函数

🌞欢迎来到C语言的世界 🌈博客主页:卿云阁 💌欢迎关注🎉点赞👍收藏⭐️留言📝 🌟本文由卿云阁原创! 🌠本阶段属于练气阶段,希望各位仙友顺利完成…

【阶段二】Python数据分析数据可视化工具使用01篇:数据可视化工具介绍、数据可视化工具安装、折线图与柱形图

本篇的思维导图: 数据可视化工具介绍 Matplotlib是最著名的绘图库,主要用于二维绘图,当然也可以进行简单的三维绘图。它提供了一整套丰富的命令,让我们可以非常快捷地用Python可视化数据,而且允许输出达到出版质量的多种图像格式。 Seaborn是在matplo…

国内电容市场份额达七成,松下如何抢占高地?

01 电容市场发展 电容器是三大电子被动元器件之一,是电子线路中不可缺少的基础元件,约占全部电子元件用量的40%,产值的66%。中国电容器行业规模增速持续高于全球规模增速,中国市场的快速增长成为拉动全球电容器行业规模增长的主要…

【Python从入门到进阶】2、Python环境的安装

接上篇《1、初识Python》 上一篇我们对Python这门编程语言进行了一个基本的了解,本篇我们来学习如何下载安装Python编程环境,以及如何使用pip管理Python包。 本篇讲解的是Windows环境下安装Python编程环境的步骤。 一、Python安装包下载 想要使用Pyth…

vue框架、element-ui组件库、font awesome图表库

一、vue 创建一个新vue项目。 vue create ProjectName 然后cd到该目录下,npm run serve启动服务器,即可打开。 二、组件库 element-ui是饿了么的,ArcoDesign是字节的,有很多。 install见官方文档:组件 | Element 导入…

黑马学SpringAMQP

目录: (1)SpringAMQP的基本介绍 (2)SpringAMQP-入门案例的消息发送 (3) SpringAMQP-入门案例的消息接收 (4)SpringAMQP-WorkQueue模型 (5)Sp…