首页 > 其他分享 >关于死锁的一些总结

关于死锁的一些总结

时间:2024-01-21 16:12:51浏览次数:23  
标签:总结 删除 死锁 线程 关于 日志 执行 等待

死锁的问题历来是面试中常问的问题, 可是在实际工作中可能几年都遇到不了一次这种问题. 不知是幸运还是不幸, 新进的这家公司刚去就遇到了两个很经典的死锁问题, 这里分享一下排查和解决思路

死锁的发生往往离不开多线程并发,我所遇到的两个场景分别是数据库的并发和代码层面的并发导致的死锁

这里需要先了解数据库的隔离级别和锁的类型

一.数据库的并发

版本: mysql8.0+的版本. 

触发背景: 项目中有通过多线程执行针对同一张表的批量删除和批量插入

死锁现象:  通过日志文件发现DeadlockException异常. 日志上下文出现多线程对同一张表的批量删除和批量插入

在数据库中复现如下:

场景1:

1.mysql数据库默认的隔离级别为可重复读[可重复读的场景下会产生间隙锁[什么是间隙锁可自行百度]]

2.开启A/B两个线程并开启事务

3.事务1执行批量删除[表索引情况: 联合索引:组成字段: A+B+C]

删除SQL: delete from table where a = 555;

当删除的数据是不存在的数据且未触发到唯一索引时, 会从555~∞ 产生间隙锁[GAP],排他锁[X锁]和意向排他锁[IX锁]

4.事务2:执行类似的批量删除:delete from table where a = 566;同样会566~∞产生锁并生成锁并进入锁等待

5.事务1:执行批量插入, 批量插入的记录数为100条, 此时数据库表需生成对应的索引记录, 而此时566~∞ 的锁已被线程B持有,进入锁等待,等待事务2释放锁

6.事务2等待事务1释放间隙锁, 事务1等待事务2 , 形成了两个线程之间的锁等待也就是死锁

7.事务提交时,因多事务间存在锁的相互等待,产生死锁. 抛出deadlock异常

解决思路:

建议将事务隔离级别调为读已提交[read-commited]

场景2: 

数据库隔离级别为读已提交[read-commited] , 但是删除的条件未触发到索引.且事务内执行的是循环删除

1.线程1:  当删除语句未触发到索引时 , 会扫描全表 , 并对符合条件的记录生成X锁,对不符合条件的记录加 IX锁

2.线程2: 当删除语句未触发到索引时 , 会扫描全表 , 并对符合条件的记录生成X锁,对不符合条件的记录加 IX锁 , 但因线程1已持有部分记录的IX锁, 线程2等待线程1释放IX锁

3.线程1: 再次执行批量删除,但是当扫描全表发现部分记录已经被线程2持有X锁 , 这里线程1需要等待线程2释放X锁.

到这里:线程2等待线程1释放IX锁 , 线程1等待线程2释放X锁 , 两者之间形成了相互等待 ,当线程1提交事务时,发现存在相互等待的情况 , 触发死锁

解决思路: 为保持代码逻辑不变的前提下 , 对表增加索引,让删除语句定位到索引上.就不会扫描全表了

可查询表perfermance_scheme.data_locks & data_lock_waits 查看锁及锁等待情况,并持有锁

以上两种情况主要是数据库层面产生的死锁 , 且这种发生死锁的情况在日志中都是可以追溯的,至少代码中会有deadlock的异常信息. 接下来分享一个代码层面的死锁

二.代码层面形成的并发

场景: 因为代码中有段处理的逻辑非常耗时 , 所以有个人把代码暴力拆成了三部分: A/B/C

其中: A/B分别通过异步线程的方式去执行, C部分要等待A&B都执行完毕后才执行.所以C段逻辑放在了主线程中执行.并通过CountDownLatch计时器进行控制等待

到这里其实也没问题, 但是B部分逻辑中有一段逻辑需要持有实例T才可执行 ,而实例T的获取逻辑中又用到了synchronized关键字

到这里,刺激的就来了, 主线程先持有了实例T,,且在等待A&B部分的异步线程执行完才会释放该实例[线程未结束时,实例会一直被主线程持有] , 而异步线程B又在等待得到实例T

好了: 主线程等待异步线程执行完好向下执行 , 异步线程在等待主线程执行完好获得实例T.两者形成了实际意义上的相互等待.也就是死锁

排除思路:

1.看日志: 日志中一切正常  打印的都是正确日志 . 可是执行到一个节点的时候就中断没有向下执行了.

2. 然后去看代码逻辑,发现断点部分在执行synchronized后就进入了等待 , 在看主线程中已经持有了该实例,  发现两个线程间存在相互等待的情况

这个难就难在:日志一切正常.代码逻辑很长.并不会像数据库那种会产生deadlock

触发原因总结

1.实例获取封装使用了synchronized进行单例控制

2.代码中使用了countdownlatch进行线程等待,且未加过期时间 .

导致一个结果: 就是两个线程永远都在相互等待,且因为是占用的内存 , synchronized和countdownlatch也不存在超时中断 , 两个线程永远不会结束 . 实例T永远不会被其他线程获得

上面是通过日志手段排查线程的思路:

还有一种就是: 本地复现的思路 , 可通过jstack命令查看线程等待状态

命令: jstack -l pid[进程ID]> jstack.log生成日志查看当前JVM中线程状态

标签:总结,删除,死锁,线程,关于,日志,执行,等待
From: https://www.cnblogs.com/kxkl123/p/17977878

相关文章

  • 线性DP简单总结
    线性DP简单总结动态规划原理可以用动态规划解决的问题,应具备三种条件:最优子结构(由小推大)无后效性(由过去推现在)子问题重叠(已经求解的子问题不必重复求解)动态规划构成“状态”“阶段”“决策”为动态规划三要素。最长上升子序列问题给定一个长度为\(n\)的序列\(A......
  • 0/1背包简单总结
    0/1背包简单总结问题:\(n\)件物品选择性放入载重为\(C\)的背包。第\(i\)件物品的重量为\(w[i]\),价值为\(v[i]\)。每个物品只有一件,你可以选择不放入背包,或者放入背包。请问该如何选择物品,在能保证物品总重量不超过背包载重的条件时,使物品的价值总和最大。解:设\(dp[i][j]\)表示......
  • 其他背包问题简单总结
    其他背包问题简单总结1.完全背包0/1背包问题:已知有第\(i\)个物品的重量\(w_{i}\),价值\(v_{i}\),以及背包的总容量\(W\)。设DP状态\(f_{i,j}\)为在只能放前\(i\)个物品的情况下,容量为\(j\)的背包所能达到的最大总价值。而完全背包,即是在\(0/1\)背包问题中,将一个物......
  • [低代码平台] 自我总结:帆软▪简道云VS金蝶▪云之家
    云平台▪架构概述云平台架构基本包括以下几个关键组件:前端用户界面:提供一个可视化的、拖拽式的界面,让用户无需编码即可设计应用程序。后端服务:执行业务逻辑、数据处理和集成服务。数据存储和管理:用于存储用户数据和应用数据的数据库系统。API和集成层:使平台能够与外部系统和数......
  • 0-1背包和完全背包,初级理解和总结
    0-1背包就是数组中元素只能取一个,完全背包就是数组中的元素能无限取。最开始接触的就是纯粹的背包问题,就是怎么装是背包价值最大,二维数组,if(j<weight[i])dp[i][j]=dp[i-1][j];elsedp[i][j]=max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);一维数组,dp[j......
  • Canal使用和安装总结
    转载请注明出处:1.定义Canal组件是一个基于MySQL数据库增量日志解析,提供增量数据订阅和消费,支持将增量数据投递到下游消费者(如Kafka、RocketMQ等)或者存储(如Elasticsearch、HBase等)的组件。 Canal感知到MySQL数据变动,然后解析变动数据,将变动数据发送到MQ或者同......
  • 关于使用SSM+JSP开发时setter、getter隐式调用问题的小结
    【版权声明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权)https://www.cnblogs.com/cnb-yuchen/p/17977495出自【进步*于辰的博客】之前使用SSM+JSP做网站开发,由于没有注意setter、getter的隐式调用问题,出现了多次bug,对开发进度影响挺大。因此,特来作这篇文章跟大家分享,帮......
  • Linux中关于磁盘的一些常见问题小记
    1.程序导致内存不够用程序导致内存不够用如果内存满则系统会自动杀死占用内存最高的进程来保护系统正常运行什么原因导致内存满:1.大量用户访问服务器(正常情况)需要我们添加内存2.由于程序导致内存满,而不是大量用户访问导致(找开发解决)3.由于网络的波动导致内存满需要......
  • 今日总结
    点击【左上角】的【File】,选择【Settings...】 选择【Plugins】在输入框中输入【Scala】等待几秒后,看到显示【Scala】点击【Install】当显示为【Installed】代表安装成功了。 步骤二、maven引包打开【pom.xml】 初始状态: 输入以下编码内容:<!--基础配置--><......
  • 2020年终总结(技术篇),重整心情、扬帆起航
    大二上篇突如其来的疫情打破了以往的平静,哪都不能去只能呆在家里,因此我收获了有史以来最长的一个寒假,在宅在家的这4个月里面,我独立做了一个大项目嘿嘿,还有一个烂大街的后台管理系统,虽然很普通但是确实我一个个敲出来的东西,很有成就感,期间历时一个多月,每天除了和家人的交际,那段时间......