死锁的成因以及解决方案

news/2024/11/17 1:56:41/

🎈专栏链接:多线程相关知识详解

目录

一.什么是死锁以及死锁的成因

Ⅰ.一个线程一把锁

Ⅱ.两个线程两把锁

Ⅲ.多个线程多把锁

二.死锁的解决方案


一.什么是死锁以及死锁的成因

死锁是一个线程加上锁了之后,解不开了

在多线程编程中,我们为了防止多线程竞争共享资源而导致数据错乱,都会在操作共享资源之前加上互斥锁,只有成功获得到锁的线程,才能操作共享资源,获取不到锁的线程就只能等待,直到锁被释放。

死锁的成因:

Ⅰ.一个线程一把锁

线程连续加锁两次,如果这个锁是不可重入锁,那必然就是死锁,synchronized是可重入锁,没有这个问题

Ⅱ.两个线程两把锁

当两个线程为了保护两个不同的共享资源而使用了两个互斥锁,那么这两个互斥锁应用不当的时候,可能会造成两个线程都在等待对方释放锁,在没有外力的作用下,这些线程会一直相互等待,就没办法继续运行,这种情况就是发生了死锁。

例如:家里门的钥匙锁车里,而车钥匙锁家里了

Ⅲ.多个线程多把锁

对于该问题有一个典型的例子:哲学家就餐问题

一张桌子,上面有一碗意大利面,和5根分散开来的筷子,桌子旁边坐着5名哲学家

 每个哲学家只做两件事情:

1.思考人生,啥也不干(线程阻塞)

2.吃面条,先拿左手边的筷子,再拿右手边的筷子,吃一会儿放回筷子

啥时候做第一件事啥时候做第二件事都是不确定的(线程随机调度)

在大部分情况这个是不会出现问题的

但是如果当5个哲学家同时要吃面条,拿起了左手边的筷子,就会出现死锁,因为右手边的筷子被其他哲学家拿走了

出现死锁的四个必要条件:

1.互斥使用.锁A被线程1占用,线程2就用不了

2.不可抢占.锁A被线程1占用,线程2不能把锁A抢过来, 除非线程1主动释放锁

3.请求和保持.有多把锁,线程1拿到锁A后,不想释放锁A,还想拿到一个锁B

4.循环等待.线程1 等待 线程2释放锁,线程2 要释放锁得等待线程3 来释放锁,线程3 释放锁得等待线程1 释放锁

二.死锁的解决方案

在上面死锁的四个必要条件当中,第一条和第二条是锁的必要条件 无法改变,

第三条的话,如果需求场景符合获取锁B的时候先释放了锁A那也是可行的,但是这个方法不普适

解决死锁的突破口就在第四条,约定好加锁的顺序,就可以打破循环等待

线程t1的加锁顺序:locker1 , locker2.  线程t2的加锁顺序:locker2 , locker1.   这样就导致了循环等待,如果调整了顺序,就可以避免循环等待

例如:给锁编号,约定加多个锁的时候,必须先加编号小的锁,后加编号大的锁

让这些哲学家约定所获取的两把锁必须先获取编号小的,再获取编号大的(而不是先拿左手的再拿右手的) 

这样子的话,从第一个哲学家开始拿编号小的筷子,直到第5个哲学家,他得先拿编号小的筷子1,才能拿编号大的筷子5,但是筷子1已经被第一个哲学家拿走了,这样的话第5个哲学家就会进入阻塞等待状态,等待第1个哲学家释放锁,这样就不会造成死锁问题

有一个更普适的解决方案 --- "银行家算法"(把所有的资源统一进行统筹分配),但不太适合实际开发


http://www.ppmy.cn/news/7687.html

相关文章

剑指offer----C语言版----第二天

目录 1. 二维数组中的查找 1.1 题目描述 1.1 思路一 1.2 思路二 1.3 思路三(最优解) 1. 二维数组中的查找 原题链接:剑指 Offer 04. 二维数组中的查找 - 力扣(LeetCode)https://leetcode.cn/problems/er-wei-shu-…

QT学习 控件(二)输入文本类

文章目录QLineEditQTextEditQTextCursorQLineEdit QLineEdit是最基本的输入控件,继承自QObject ,常用于短行的输入。 构造函数: 可以指定一个默认文本以及父窗口 QLineEdit(const QString &contents, QWidget *parent nullptr)QLineE…

前端面试题之计算机网络篇--HTTP协议

HTTP协议 1. GET和POST的请求的区别 GET和POST方法 GET和POST方法都是HTTP中的方法 什么是 HTTP? 超文本传输协议(Hypertext Transfer Protocol,缩写 HTTP)旨在启用客户端和服务器之间的通信。 HTTP 充当客户端和服务器之间的…

花费数小时,带你学透Java数组,这些常用方法你还记得吗?

推荐学习专栏:Java 编程进阶之路【从入门到精通】 文章目录1. 数组2. 一维数组2.1 声明2.2 初始化2.3 使用3. 二维数组3.1 声明3.2 初始化3.3 使用4. 数组在内存中的分布5. 数组常用的方法5.1 Arrays.toString方法5.2 Arrays.copyOf方法5.3 Arrays.copyOfRange方法5…

Qt编写雷达模拟仿真工具1-背景布局

一、前言 雷达模拟仿真工具,整体结构采用的QGraphicsView框架,背景布局采用的分层绘制,这样可以控制该需要重新绘制的重新绘制,不需要重新的绘制的就没必要再多余的浪费,这里定义了一个GraphicsBackGroundItem类继承自…

freeswitch的gateway实现出中继的主备方案

概述 freeswitch是一款简单好用的VOIP开源软交换平台。 某些呼叫场景中,我们有2条出中继线路可选,2条出中继需要按照主备模式来配置,优先使用主中继呼叫,当主中继出现问题时,呼叫自动转移到备用中继呼叫。 本节中&a…

C语言基础 — ( 顺序程序设计[ 运算符、表达式 ] )

欢迎小伙伴的点评✨✨ 本篇章系列是对C语言的深度思考和总结、关于C语言内容会持续更新。 文章目录前言一、C运算符1.1、算数运算符1.2、关系运算符1.3、逻辑运算符1.4、位运算符1.5、赋值运算符1.6、条件运算、指针运算、字节运算1.7、C中的运算优先级二、不同类型数据间的混合…

Spring boot分布式链路追踪

Spring boot分布式链路追踪前言演示项目核心依赖一、系统配置文件 日志文件路径配置二、日志文件 logback.xml 其中重要的标志是“requestId”字眼三、配置全局拦截器 RequestIdTraceInterceptor.java 拦截交互请求带有 “requestId” 字眼的值四、实际使用五、效果展示 MDC.pu…