1. 最简单的死锁
最常见的死锁 是因为一个事务执行时间过长,而导致另外一个事务 无法 访问 被被该事务锁定的资源,最终 超时 而导致的死锁异常. 这种情况无非有两种解决方案,一是性能调优。 二是当该事务遇到等待超时导致的死锁异常后,继续让该事务 re-try.
2. 互相等待 -- 死锁
这种 死锁的异常情况特殊,两个极短的事务 在 高并发的环境下也可能发生 相互等待 -- 死鎖 的情況.
a) 怎样导致的?
总的来说,是因为两个事务 对共有资源的CUD 执行顺序 不同导致的. 如下,
事务1: A -- > B
事务2: B -- > A
在高并发情况下,如果 相同时间内,事务1 处理完 对资源A的CUD 同时 事务2 处理完 对资源B 的CUD。 这个时候 事务1 要对 B 资源 CRUD 同时 事务2也要对 A资源 CRUD, 而此时, 事务1 锁住了A资源,事务2锁住了B资源,所以 事务1需要等待事务2释放B资源 才能继续对B资源操作,相反事务2需要等待事务1释放A资源 才能继续对A资源操作。 这样 两个事务互相等待 锁释放 而导致死锁
b) 如何解決?
唯一的办法就是 让这两个事务 对共有资源的CUD 执行顺序 一样。
事务1: A -- > B
事务2: A -- > B
有趣的问题 如果事务2 是 A --> B --> A 而事务1保持不变, 当事务2 执行完B资源操作 再次对A资源操作的时候 会不会出现死锁呢, 看起来如果事务1同时也执行到对B资源操作的时候 - 好像会, 但答案是不会.
原因很简单,因为 A资源已经被 事务2 锁定, 事务1 不会有机会启动,只有等待 事务2 释放 A资源锁后,得到该锁的事务1才能开始执行。
同样, 如果我们 这样设定执行的顺序来解决这样的问题,是不是会导致 线程相互等待的时间过长 而导致性能大幅降低呢 ?( 如事务2 先执行,那么事务1就必须等待 事务2执行完后,释放对A 资源的锁后, 得到该锁的事务1 才能继续执行)
我们完全没必要有这种担忧, 原因很简单,大型系统中, 即便是在高并发状态下,两个或者多个不同线程的事务 能同时在千万条数据中 并发访问到(这里指 CUD 操作)完全相同的数据 的概率是相当小的 。
产生死锁的必要条件 虽然进程在运行过程中,可能发生死锁,但死锁的发生也必须具备一定的条件,死锁的发生必须具备以下四个必要条件 。
1 )互斥条件: 指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。
2 )请求和保持条件: 指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。
3 )不剥夺条件: 指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。(既是没有Timeout 或者 更高优先级剥夺 的情况)
4 )环路等待条件: 指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。
死锁的详细说明