目录

各种锁..

死锁

两个或者两个以上的进程或线程在执行过程中,因争夺资源而造成的一种等待的现象,没有外力作用,他们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在相互等待的进程称为死锁进程

死锁发生的条件

  • 互斥条件

    一个线程占用了某个资源,那么其他线程必须处于等待状态,直到改资源被释放

  • 请求和保持条件

    g1线程已经又了资源r1,这个时候又申请r2资源,此时r2被其他资源占用,g1就必须等待,同时又不释放自己占用的r1

  • 不剥夺条件

    线程已获得的资源,在未使用完之前,不能被其他线程剥夺,只能在使用完之后由自己释放

  • 环路等待条件

    线程队列{g1 ,g2, g3},g1等待g2,g2等待g3,g3等待g1,因此环路等待,g1,g2,g3都无法执行

解决死锁的办法

  • 如果并发查询多个表,约定访问顺序
  • 在同一个事务中尽可能做到一次锁定获取所需要的资源
  • 对于容易产生死锁的业务场景,尝试升级锁颗粒度,使用表级锁
  • 采用分布式事务锁或者使用乐观锁

活锁

g1可以使用资源,但是它比较礼貌,让别的先执行。

g2也可以使用资源,它也很礼貌,让别的先执行。

最后的结果就是两个线程都无法使用资源

活锁常常发生的场景

在事务处理中,如果不能成功处理某个消息,那么消息处理机制将会滚事务,并且将它放在队列的开头,这样错误的事务一直被不断的执行。

造成这件事的原因是,过度的错误恢复代码造成的,它错误的将不可修复的错误认为是可修复的错误

当多个相互协作的线程都对彼此进行响应,并且修改自己的状态,使得任何一个线程都无法继续执行时,就导致了活锁

就像两个过于礼貌的人在路上相遇,他们彼此让路,然后在另一条路上相遇,然后他们就一直这样避让下去。

解决办法:

在重试机制中引入随机性,例如在网络上发送数据包2,如果监测到冲突,都要停止并在一段时间后重发,如果都在1秒后重发,还是会冲突,所以引入随机性可以解决该类问题。

活锁和死锁的区别

活锁的实体时在不断的改变状态,而死锁的实体是一直等待。

活锁又可能自行解开,死锁不能。

饥饿锁

饥饿是指一个可运行的进程尽管能继续执行,但是被调度器无限期的忽视,而不能被调度执行的情况。

常见的情况就是优先级高的线程一直抢占优先级低的线程的资源,导致优先级低的线程一直没有办法执行。

饥饿锁和死锁的不同

饥饿锁在一段时间内,优先级比较低的线程最终还是会执行的,比如高优先级的线程执行完之后释放了资源