导读: 虽然锁在一定程度上能够解决并发问题,但稍有不慎,就可能造成死锁。本文介绍死锁的产生及处理。
死锁的产生和预防
发生死锁的必要条件有4个,分别为互斥条件、不可剥夺条件、请求与保持条件和循环等待条件,如图1所示。
▲图 死锁的必要条件
1. 互斥条件
在一段时间内,计算机中的某个资源只能被一个进程占用。此时,如果其他进程请求该资源,则只能等待。
2. 不可剥夺条件
某个进程获得的资源在使用完毕之前,不能被其他进程强行夺走,只能由获得资源的进程主动释放。
3. 请求与保持条件
进程已经获得了至少一个资源,又要请求其他资源,但请求的资源已经被其他进程占有,此时请求的进程就会被阻塞,并且不会释放自己已获得的资源。
4. 循环等待条件
系统中的进程之间相互等待,同时各自占用的资源又会被下一个进程所请求。例如有进程A、进程B和进程C三个进程,进程A请求的资源被进程B占用,进程B请求的资源被进程C占用,进程C请求的资源被进程A占用,于是形成了循环等待条件,如图2所示。
▲图2 死锁的循环等待条件
需要注意的是,只有4个必要条件都满足时,才会发生死锁。
处理死锁有4种方法,分别为预防死锁、避免死锁、检测死锁和解除死锁,如图3所示。
▲图3 处理死锁的方法
在实际工作中,通常采用有序资源分配法和银行家算法这两种方式来避免死锁,大家可自行了解。
02
MySQL中的死锁问题
在MySQL 5.5.5及以上版本中,MySQL的默认存储引擎是InnoDB。该存储引擎使用的是行级锁,在某种情况下会产生死锁问题,所以InnoDB存储引擎采用了一种叫作等待图(wait-for graph)的方法来自动检测死锁,如果发现死锁,就会自动回滚一个事务。
接下来,我们看一个MySQL中的死锁案例。
第一步: 打开终端A,登录MySQL,将事务隔离级别设置为可重复读,开启事务后为account数据表中id为1的数据添加排他锁,如下所示。
第二步: 打开终端B,登录MySQL,将事务隔离级别设置为可重复读,开启事务后为account数据表中id为2的数据添加排他锁,如下所示。
第三步: 在终端A为account数据表中id为2的数据添加排他锁,如下所示。
mysql> select * from account where id =2 for update;
此时,线程会一直卡住,因为在等待终端B中id为2的数据释放排他锁。
第四步: 在终端B中为account数据表中id为1的数据添加排他锁,如下所示。
mysql> select * from account where id =1 for update;
ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
此时发生了死锁。通过如下命令可以查看死锁的日志信息。
show engine innodb status\G
通过命令行查看LATEST DETECTED DEADLOCK选项相关的信息,可以发现死锁的相关信息,或者通过配置innodb_print_all_deadlocks(MySQL 5.6.2版本开始提供)参数为ON,将死锁相关信息打印到MySQL错误日志中。
在MySQL中,通常通过以下几种方式来避免死锁。
本书摘编自《深入理解分布式事务:原理与实践》,经出版方授权发布。
推荐语: 本书的广度与深度兼备、理论与实战兼顾的分布式事务专著,它从基础知识、解决方案、原理分析、源码实现、工程实战5个维度对分布式事务做了全面、细致的讲解,试图解决你在实践中遇到的所有关于分布式事务的问题。
作者简介:
肖宇
分布式事务架构专家,Apache ShenYu(incubating)网关创始人,Dromara开源组织创始人,Hmily、RainCat、Myth等分布式事务框架的作者,Apache ShardingSphere提交者。
热爱开源,追求优雅代码。有丰富的微服务架构经验,尤其擅长微服务技术栈中的分布式事务、微服务架构、分布式数据库、API网关等解决方案。
冰河
互联网高级技术专家、MySQL技术专家、分布式事务架构专家。
多年来,一直致力于分布式系统架构、微服务、分布式数据库、分布式事务与大数据技术的研究,在高并发、高可用、高可扩展性、高可维护性和大数据等领域拥有丰富的架构经验。
冰河大佬,李海翔大佬,肖宇大佬 在本月22号,23号有直播技术分享,大家不要错过
送两本《深入理解分布式事务:原理与实践》
如何免费获得该书呢?
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://xiaoxuzhu.blog.csdn.net/article/details/124156409
内容来源于网络,如有侵权,请联系作者删除!