各种锁..
锁
死锁
两个或者两个以上的进程或线程在执行过程中,因争夺资源而造成的一种等待的现象,没有外力作用,他们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在相互等待的进程称为死锁进程
死锁发生的条件
-
互斥条件
一个线程占用了某个资源,那么其他线程必须处于等待状态,直到改资源被释放
-
请求和保持条件
g1线程已经又了资源r1,这个时候又申请r2资源,此时r2被其他资源占用,g1就必须等待,同时又不释放自己占用的r1
-
不剥夺条件
线程已获得的资源,在未使用完之前,不能被其他线程剥夺,只能在使用完之后由自己释放
-
环路等待条件
线程队列{g1 ,g2, g3},g1等待g2,g2等待g3,g3等待g1,因此环路等待,g1,g2,g3都无法执行
解决死锁的办法
- 如果并发查询多个表,约定访问顺序
- 在同一个事务中尽可能做到一次锁定获取所需要的资源
- 对于容易产生死锁的业务场景,尝试升级锁颗粒度,使用表级锁
- 采用分布式事务锁或者使用乐观锁
活锁
g1可以使用资源,但是它比较礼貌,让别的先执行。
g2也可以使用资源,它也很礼貌,让别的先执行。
最后的结果就是两个线程都无法使用资源
活锁常常发生的场景
在事务处理中,如果不能成功处理某个消息,那么消息处理机制将会滚事务,并且将它放在队列的开头,这样错误的事务一直被不断的执行。
造成这件事的原因是,过度的错误恢复代码造成的,它错误的将不可修复的错误认为是可修复的错误
当多个相互协作的线程都对彼此进行响应,并且修改自己的状态,使得任何一个线程都无法继续执行时,就导致了活锁
就像两个过于礼貌的人在路上相遇,他们彼此让路,然后在另一条路上相遇,然后他们就一直这样避让下去。
解决办法:
在重试机制中引入随机性,例如在网络上发送数据包2,如果监测到冲突,都要停止并在一段时间后重发,如果都在1秒后重发,还是会冲突,所以引入随机性可以解决该类问题。
活锁和死锁的区别
活锁的实体时在不断的改变状态,而死锁的实体是一直等待。
活锁又可能自行解开,死锁不能。
饥饿锁
饥饿是指一个可运行的进程尽管能继续执行,但是被调度器无限期的忽视,而不能被调度执行的情况。
常见的情况就是优先级高的线程一直抢占优先级低的线程的资源,导致优先级低的线程一直没有办法执行。
饥饿锁和死锁的不同
饥饿锁在一段时间内,优先级比较低的线程最终还是会执行的,比如高优先级的线程执行完之后释放了资源