关于死锁

最近在项目中遇到了死锁的问题,在解决死锁的同时,也比较系统的理解了相关的锁,这里记录一下。
了解一下innodb中的锁
基本锁:
共享锁(S锁):读锁:事务T对数据A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的S锁。这保证了其他事务可以读A,但在T释放A上的S锁之前不能对A做任何修改。

排他锁(X锁):写锁。事务T对数据A加上X锁,事务T可以读A也可以修改A,其他事务不能再对A加任何锁,直到T释放A上的锁。这保证了其他事务在T释放A上的X锁之前不能再读取和修改A。

注意:如果2个JOB同时获取到了数据A(就是同时给数据A加上了S锁),因为jobA给数据A添加S锁后,jobB也可以对数据A添加S锁。那么当2个JOB都需要开始对数据A进行修改时,那么都要同时升级到X锁,在这种情况下就会出现死锁(jobA等待jobB释放S锁,jobB等待jobA释放S锁)。

锁与索引的关系
主键本身就是索引。innodb对于主键使用了聚簇索引,这是一种数据存储方式,表数据是和主键一起存储。主键索引的叶结点存储行数据。普通索引,其叶结点存储的是主键值(普通索引锁住了,也会锁住相对应的的主键左右)。

分析下索引和锁的关系
id:主键 token:二级索引(非唯一)
1)update table_1 set msg='a' where id=1;
由于id是主键,所以锁定table_1表中的此行记录。(X锁)

2)update table_1 set msg='a' where token='b';
由于token是二级索引,会先锁定这个二级索引(表中的记录token的值为b的行,有几行锁定几行),然后锁定相应主键所对应的记录。(X锁)

3)update table_1 set msg='a' where msg='b';
没有索引,是全表扫描,会对表中的各个记录加上X锁。

以上的是在数据库事务隔离级别是RC(已提交读)级别下的锁。

数据库事务隔离级别:1)未提交读(Read uncommitted);2)已提交读(Read committed(RC));3)可重复读(Repeatable read(RR));4)可串行化(Serializable)
提交读(RC):只能读取到已经提交的数据。
可重复读(RR):在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。

在RC的级别下的锁,可以防止不同事务数据修改提交时造成数据冲突的情况。但是在做insert的时候会出现幻读。

[img]http://dl2.iteye.com/upload/attachment/0123/8407/6135487f-0950-335c-8fd3-9b9460a4abe1.png[/img]

innodb在RR隔离级别中引入了GAP锁,可以避免幻读发生。
在事务A执行update语句的时候,innodb首先会和RC级别一样,给索引上的记录添加上X锁,此外,还在非唯一索引token值与相邻两个索引的区间加上锁。这样在事务B执行insert语句,然后commit;时会首先检查这个区间是否被锁上,如果被锁上,则不能立即执行,需要等待该gap锁被释放。这样就能避免幻读问题。

造成死锁的原因:
1)不同表相同记录行锁冲突

[img]http://dl2.iteye.com/upload/attachment/0123/8411/8a25a1c9-29f9-3491-9e13-178896fb27a8.png[/img]

2)相同表记录行锁冲突:2个job做更新操作

[img]http://dl2.iteye.com/upload/attachment/0123/8415/c69e275e-2292-33f6-b7b6-2fa3786ba6f8.png[/img]
3)不同索引锁冲突:事务A在执行时,除了了在二级索引加锁,还会在主键上加锁。事务B只会在主键上加锁。

[img]http://dl2.iteye.com/upload/attachment/0123/8417/182f664a-6c65-34b0-827c-d5884152ddca.png[/img]
4)GAP锁冲突

[img]http://dl2.iteye.com/upload/attachment/0123/8425/7ee30e8c-622d-36e8-82cf-8e494442200c.png[/img]
<think>好的,用户现在想了解死锁的定义、产生原因及解决方法。我之前已经回答过TCP/IP协议的问题,现在需要根据用户提供的引用材料来组织回答。首先,我需要确认用户提供的四个引用内容,确保正确引用到回答中。 用户给出的引用[1]提到死锁的定义、产生条件和解决办法,特别是检测方法是通过检查进程和资源的有向图是否存在环路。引用[2]讨论了可重入锁和普通锁加锁两次是否导致死锁的情况。引用[3]和[4]则涉及死锁原因,如资源竞争,以及解决方法如回退和随机等待。 接下来,我需要按照用户之前的回答结构来组织内容,确保使用正确的中文和格式,如行内数学公式用$...$,独立公式用$$...$$,但可能这个回答中数学公式不多。然后需要生成相关问题,并确保引用标识正确添加。 首先定义死锁,根据引用[1],死锁是多个进程互相等待对方释放资源,导致无法推进的状态。产生条件包括互斥、持有等待、不可剥夺和循环等待。解决办法有预防、避免、检测和解除。需要引用[1][4]来支持资源竞争的原因。 在产生原因部分,引用[4]提到系统资源竞争,特别是不可剥夺资源。引用[2]中的锁重入问题也是原因之一。解决方法中,引用[3]提到的回退和随机等待需要包含,同时要提到死锁检测,如引用[1]中的环路检测。 最后生成相关问题,需要覆盖定义、条件、应用场景、检测方法、可重入锁等,参考用户之前的示例问题结构。确保每个引用在回答中有对应的标注,比如[^1]、[^2]等,并且引用位置自然。</think>#### 死锁的定义与核心原理 **死锁**指多个进程(或线程)因竞争资源陷入互相等待的状态,导致所有进程无法继续执行。这种现象类似于交通堵塞中的“环形等待”,每个进程都持有对方所需的资源且不释放[^1][^4]。 --- #### 一、死锁产生的四大必要条件 1. **互斥条件** 资源具有独占性(如打印机、数据库连接),同一时间只能被一个进程使用[^4]。 2. **持有并等待** 进程已持有至少一个资源,同时请求其他进程占有的资源且不释放已有资源[^1][^4]。 3. **不可剥夺** 资源只能由持有者主动释放,无法被系统强制回收(如未保存的文件句柄)[^4]。 4. **循环等待** 存在进程集合 $\{P_1, P_2, ..., P_n\}$,其中每个 $P_i$ 都在等待 $P_{i+1}$ 持有的资源,且 $P_n$ 等待 $P_1$ 的资源,形成环形依赖[^1][^3]。 --- #### 二、死锁产生的直接原因 1. **资源竞争** 当多个进程争夺不可剥夺资源(如硬件设备)且资源数量不足时,可能引发僵局[^4]。 2. **编程设计缺陷** - **不可重入锁**:若线程对同一锁连续加锁两次且锁不可重入,会导致自身阻塞(如引用[^2]中描述的线程自阻塞)。 - **锁顺序不一致**:线程以不同顺序获取多把锁,可能形成循环等待[^3]。 3. **系统调度策略** 操作系统未合理分配资源或未检测资源分配图,可能放大死锁风险[^1]。 --- #### 三、死锁解决方案 | **方法** | **实现原理** | **典型场景** | |-----------------|----------------------------------------------------------------------------|----------------------------------| | **预防策略** | 破坏任一必要条件:<br> - 资源一次性分配(破坏持有等待)<br> - 允许资源剥夺(破坏不可剥夺性) | 嵌入式系统、实时控制系统 | | **避免策略** | 通过银行家算法预判资源分配是否安全 | 资源类型固定的场景(如内存管理) | | **检测与恢复** | 周期性地构建资源分配图,检测环路:<br> $$G=(V,E) \text{ 中存在环} \Rightarrow \text{死锁}$$<br> 发现后强制终止进程或回滚操作[^1][^3] | 数据库事务管理、分布式系统 | | **忽略策略** | 假设死锁概率极低(如UNIX系统默认处理方式) | 通用操作系统 | --- #### 四、开发中的实践建议 1. **锁顺序标准化** 多线程编程中固定锁的获取顺序(如按内存地址升序),避免循环等待。 2. **使用可重入锁** 通过支持重入的锁(如Java的`ReentrantLock`)防止线程自阻塞[^2]。 3. **超时回退机制** 若获取锁超时,释放已持有锁并随机等待后重试(如引用中的回退策略)。 --- #### 五、典型问题解析 **问题**:线程对同一不可重入锁连续加锁两次会死锁吗? **答案**: - **可重入锁**:允许线程重复加锁,计数器记录锁次数,不会死锁。 - **不可重入锁**:第二次加锁时线程自身被阻塞,导致死锁[^2]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值