【多线程】死锁 详解
死锁
- 一. 死锁是什么
- 二. 死锁的场景
- 1. 一个线程一把锁
- 2. 两个线程两把锁
- 3. N 个线程 M 把锁
- 三. 死锁产生的四个必要条件
- 四. 如何避免死锁
一. 死锁是什么
死锁是这样一种情形:
多个线程同时被阻塞,因为每个进程都在等其他线程释放某些资源,同时又不释放自己占用的资源,从而导致系统陷入僵局。
由于线程被无限期地阻塞,因此程序不可能正常终止。
死锁是一种严重的 BUG!! 导致一个程序的线程 “卡死”, 无法正常工作!
二. 死锁的场景
1. 一个线程一把锁
一个线程对同一把锁上锁多次,如果该锁是 不可重入锁 就会死锁,否则是 可重入锁 就不会死锁。
代码举例:
Object locker = new Object();// 对 locker 第一次加锁synchronized (locker) {// 对 locker 第二次加锁synchronized (locker) {// do something}}
因为 synchronized 是可重入锁, 所以它并不会导致死锁,但如果换成不可重入锁的话就会死锁。
2. 两个线程两把锁
A 持有 lock1, 等待 lock2, B 持有 lock2, 等待 lock1。
所以情况就是:
A 说:你先给我,我再给你。
B 说:我不,你先给我,我再给你。
比如:屋子的钥匙锁车里了,车钥匙锁屋里了。
代码举例:
class Test{public static void main(String[] args) throws InterruptedException {Object lock1 = new Object();Object lock2 = new Object();Thread threadA = new Thread(() -> {synchronized (lock1) {System.out.println("Thread A: Holding lock 1...");try { Thread.sleep(1000); } catch (InterruptedException e) {}System.out.println("Thread A: Waiting for lock 2...");synchronized (lock2) {System.out.println("Thread A: Acquired lock 2.");}}});Thread threadB = new Thread(() -> {synchronized (lock2) {System.out.println("Thread B: Holding lock 2...");try { Thread.sleep(1000); } catch (InterruptedException e) {}System.out.println("Thread B: Waiting for lock 1...");synchronized (lock1) {System.out.println("Thread B: Acquired lock 1.");}}});threadA.start();threadB.start();}
}
3. N 个线程 M 把锁
为了进一步阐述死锁的形成, 我们引用有名的 “哲学家就餐问题”.
- 有个桌子, 围着一圈 哲学家, 桌子中间放着一盘意大利面. 每个哲学家两两之间, 放着一根筷子.
-
每个哲学家只做两件事: 思考人生 或 吃面条. 思考人生时就会放下筷子. 吃面条就会拿起左右两边的筷子(先拿左边, 再拿右边).
-
如果哲学家发现筷子拿不起来了(被别人占用了), 就会阻塞等待.
-
假如出现极端情况:同一时刻, 五个 哲学家 同时拿起左手边的筷子, 然后再尝试拿右手的筷子, 就会发现右手的筷子都被占用了. 由于哲学家们互不相让, 这个时候就形成了 死锁.
三. 死锁产生的四个必要条件
- 互斥使用,即当资源被一个线程使用(占有)时,别的线程不能使用。
- 不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。
- 请求和保持,即当资源请求者在请求其他的资源的同时保持对原有资源的占有。
- 环路等待,即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路。
四. 如何避免死锁
当上述四个条件都成立的时候,便形成死锁。当然,死锁的情况下如果打破上述任何一个条件,便可让死锁消失。
其中最容易破坏的就是 “循环等待”.
最常用的一种死锁阻止技术就是锁排序:
假设有 N 个线程尝试获取 M 把锁, 就可以针对 M 把锁进行编号 (1, 2, 3…M).
N 个线程尝试获取锁的时候, 都按照固定的按编号由小到大顺序来获取锁. 这样就可以避免环路等待.
比如上面两个线程两把锁死锁的例子:
约定好先获取 lock1, 再获取 lock2 , 就不会环路等待.
class Test{public static void main(String[] args) throws InterruptedException {Object lock1 = new Object();Object lock2 = new Object();Thread threadA = new Thread(() -> {synchronized (lock1) {System.out.println("Thread A: Holding lock 1...");try { Thread.sleep(1000); } catch (InterruptedException e) {}System.out.println("Thread A: Waiting for lock 2...");synchronized (lock2) {System.out.println("Thread A: Acquired lock 2.");}}});Thread threadB = new Thread(() -> {synchronized (lock1) {System.out.println("Thread B: Holding lock 1...");try { Thread.sleep(1000); } catch (InterruptedException e) {}System.out.println("Thread B: Waiting for lock 2...");synchronized (lock2) {System.out.println("Thread B: Acquired lock 2.");}}});threadA.start();threadB.start();}
}
好啦! 以上就是对 死锁 的讲解,希望能帮到你 !
评论区欢迎指正 !
相关文章:

【多线程】死锁 详解
死锁 一. 死锁是什么二. 死锁的场景1. 一个线程一把锁2. 两个线程两把锁3. N 个线程 M 把锁 三. 死锁产生的四个必要条件四. 如何避免死锁 一. 死锁是什么 死锁是这样一种情形: 多个线程同时被阻塞,因为每个进程都在等其他线程释放某些资源,…...
成考[专升本政治]科目必背知识点
1. 马克思主义哲学研究的对象是:关于自然、社会、思维发展的一般规律。 2. 对待马克思主义的科学态度是:坚持和发展。 3. 物质的唯一特性是客观实在性。这里的客观实在是指:不以人的意志为转移。 4. 在实际工作中,要注意掌握…...

spring boot 使用AOP+自定义注解+反射实现操作日志记录修改前数据和修改后对比数据,并保存至日志表
一、添加aop starter依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId> </dependency>二:自定义字段翻译注解。(修改功能时,需要显示如…...

【深度学习】Pytorch 系列教程(二):PyTorch数据结构:1、Tensor(张量): GPU加速(GPU Acceleration)
目录 一、前言 二、实验环境 三、PyTorch数据结构 0、分类 1、张量(Tensor) 1. 维度(Dimensions) 2. 数据类型(Data Types) 3. GPU加速(GPU Acceleration) 一、前言 ChatGP…...

多线程|多进程|高并发网络编程
一.多进程并发服务器 多进程并发服务器是一种经典的服务器架构,它通过创建多个子进程来处理客户端连接,从而实现并发处理多个客户端请求的能力。 概念: 服务器启动时,创建主进程,并绑定监听端口。当有客户端连接请求…...

云计算——ACA学习 云计算分类
作者简介:一名云计算网络运维人员、每天分享网络与运维的技术与干货。 公众号:网络豆 座右铭:低头赶路,敬事如仪 个人主页: 网络豆的主页 目录 写在前面 前期回顾 本期介绍 一.云计算分类 1.公有云…...

3 分钟,带你了解低代码开发
一、低代码平台存在的意义 传统软件开发交付链中,需求经过3次传递,用户→业务→架构师→开发,每一层传递都可能使需求失真,导致最终交付的功能返工。 业务的变化促使软件开发过程不断更新、迭代和演进,而低代码开发即是…...

小白学Unity03-太空漫游游戏脚本,控制飞船移动旋转
首先搭建好太阳系以及飞机的场景 需要用到3个脚本 1.控制飞机移动旋转 2.控制摄像机LookAt朝向飞机和差值平滑跟踪飞机 3.控制各个星球自转以及围绕太阳旋转(rotate()和RotateAround()) 1.控制飞机移动旋转的脚本 using System.Collections; using…...

接口自动化测试推荐用什么框架?
在推荐接口自动化测试框架时,需要考虑多个因素,包括项目需求、技术栈、团队经验和个人偏好。 以下是几个常用的接口自动化测试框架供你参考: Postman: Postman是一个功能强大且易于上手的接口测试工具,它提供了许多…...

防火墙 FireWall
这里写自定义目录标题 一、概述二、防火墙分类三、防火墙性能四、硬件防火墙定义五、硬件防火墙作用(拓扑图 ups)六、硬件防火墙品牌七、软件防火墙八、iptables一、iptables是什么?二、netfilter/iptables功能三、iptables概念四、iptables中…...

【Linix-Day12-线程同步和线程安全】
线程同步 和 线程安全 线程同步 除了信号量和互斥锁(互斥锁和条件变量上次介绍过),还有两种方式同步 1.读写锁 当同时对一块内存读写时,会出现下列问题,故而引入读写锁 接口介绍: 1.int pthread_rwloc…...
C++中使用嵌套循环遍历多维数组
C中使用嵌套循环遍历多维数组 一维数组:数组元素可以看做是一行数据。 二维数组:更像是一个表格,既有行数据又有列数据。 C没有提供二维数组类型,但用户可以创建每个元素本身都是数组的数组。例如,假设要存储 5 个城…...

linux入门---命名管道
如何创建命名管道 使用mkfifo函数就可以在程序里面创建管道文件,该函数的声明如下: 该函数需要两个参数,第一个参数表示要在哪个路径下创建管道文件并且这个路径得待上管道文件的名字,因为每个文件都有对应的权限,所…...

SpringBoot2.0入门(详细文档)
文章目录 Springboot是什么Springboot2.x依赖环境和版本新特性说明为什么学习Springboot从springboot优点来看从未来发展的趋势来看 开发环境Spring Boot开发环境搭建和项目启动jdk 的配置Spring Boot 工程的构建maven配置IDEA 快速构建maven 创建工程常用注解 完整代码 Spring…...

Aztec的隐私抽象:在尊重EVM合约开发习惯的情况下实现智能合约隐私
1. 引言 Aztec的架构,不同于当前“通过EVM兼容执行环境”所实现的区块链水平扩容趋势。Aztec内部笑称其构建的为首个非zkEVM协议。 Aztec专注于实现: 成为理解和需要智能合约隐私的开发者的终极解决方案。 Aztec为开发者提供构建隐私优先app所需的网…...
【Vue】详细介绍Vue项目的目录结构及各个核心文件的示例代码
Vue.js并没有严格的文件和目录结构要求,但一般情况下,我们的Vue项目目录结构如下: ├── node_modules/ # 项目依赖的 node 模块 ├── public/ # 公共资源目录 │ ├── favicon.ico # 网页图标 │ └──…...
【人大金仓】迁移MySql数据库到人大金仓,出现sys_config表重复
需要迁移的数据库中有张表名称为sys_config,查询的时候查询结果不符合我们的预期,经咨询金仓售后人员后得知和系统表重名… 解决问题方法如下: alter database [数据库名] set search_path to "$user", [模式名,(可选&…...

linux内核进程间通信IPC----消息队列
消息队列:提供一种从一个进程向另一个进程发送一个数据块的方法。与FIFO相比,消息队列的优势在于,它独立于发送和接收进程而存在。 1.链表式结构组织,存放于内核。 2.通过队列标识来引用。 3.通过一个数据类型来索引指定的数据。 …...

PHP实现微信小程序状态检测(违规、暂停服务、维护中、正在修复)
实现原理 进入那些状态不正常的小程序会被重定向至一个Url,使用抓包软件抓取这个Url,剔除不必要参数,使用cURl函数请求网页获得HTML内容,根据内容解析出当前APPID的小程序的状态。 代码 <?php// 编码header(Content-type:ap…...
ubuntu在线直接升级
前几天VMware上安装了ubuntu,当时的内核版本支持(ipguard,加密软件),后来ubuntu自动升级了linux内核,导致加入软件不支持,无法访问加密文件了。后来加密软件商更新了软件,但还是赶不上linux内核更新速度,还…...
React Native 导航系统实战(React Navigation)
导航系统实战(React Navigation) React Navigation 是 React Native 应用中最常用的导航库之一,它提供了多种导航模式,如堆栈导航(Stack Navigator)、标签导航(Tab Navigator)和抽屉…...

基于ASP.NET+ SQL Server实现(Web)医院信息管理系统
医院信息管理系统 1. 课程设计内容 在 visual studio 2017 平台上,开发一个“医院信息管理系统”Web 程序。 2. 课程设计目的 综合运用 c#.net 知识,在 vs 2017 平台上,进行 ASP.NET 应用程序和简易网站的开发;初步熟悉开发一…...

UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...

ServerTrust 并非唯一
NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...
数据库分批入库
今天在工作中,遇到一个问题,就是分批查询的时候,由于批次过大导致出现了一些问题,一下是问题描述和解决方案: 示例: // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...

AI书签管理工具开发全记录(十九):嵌入资源处理
1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...
JS设计模式(4):观察者模式
JS设计模式(4):观察者模式 一、引入 在开发中,我们经常会遇到这样的场景:一个对象的状态变化需要自动通知其他对象,比如: 电商平台中,商品库存变化时需要通知所有订阅该商品的用户;新闻网站中࿰…...
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found", "n…...
Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?
Pod IP 的本质与特性 Pod IP 的定位 纯端点地址:Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址(如 10.244.1.2)无特殊名称:在 Kubernetes 中,它通常被称为 “Pod IP” 或 “容器 IP”生命周期:与 Pod …...