多线程(死锁)

什么是死锁

先介绍独占性的资源 : 即再同一时刻某种资源只能由一个进程使用, 比如打印机, 同一时刻一台打印机不能有两个输出结果
那么两个进程独占性的访问某个资源, 从而等待另一个资源的执行结果, 会导致两个进程都阻塞, 并且两个进程都不会释放各自的资源, 这种情况就是 “死锁”


死锁的典型情况

  1. 在一个线程中, 对同一个对象连续加锁多次, 如果是不可重入锁, 就会产生死锁问题
  2. 两个线程两把锁, 线程 t1 和 t2 各自针对 对象 A 和 B 加锁, 再尝试获取对方已经加锁的对象
  3. 多个线程多把锁 (典型实例 : 哲学家就餐问题)

可重入不可重入

在一个线程中, 在已经给一个对象上锁(还未解锁的情况下), 再次尝试给该对象加锁

可重入锁(例如 synchronized) , 会在锁内记录是哪个线程拥有我, 如果该线程再次尝试给我加锁, 就允许 (实际上只加了一次锁, 后续的再次加锁只是允许你使用该对象, 不是再多加一次锁)

不可重入, 在一个线程内, 如果针对一个对象多次加锁, 由于第一次加锁过后没有解锁, 所以后续的加锁操作就会进入锁竞争, 前面加的锁不释放, 后面在等前面的锁释放, 就会造成死锁情况


死锁的四个必要条件

  1. 互斥使用 (锁的基本特征): 线程 t1 拿到了锁, 线程 t2 就只能等待
  2. 不可抢占: 线程 t1那到了锁, 必须是 t1 主动释放锁, 不能是因为别的线程需要使用的时候, 强行抢夺锁
  3. 请求和保持: 线程 t1 拿到 锁A 之后, 再尝试获取 锁B, 此时 t1 仍持有 锁A, 不会因为获取 锁B 就把 锁A 给释放了
  4. 循环等待: 线程 t1 持有锁A, 线程 t2 持有 锁B, 在此基础上 线程 t1尝试获取 锁B, 并且线程 t2 尝试获取 锁A, 二者都不释放自己拥有的锁, 又尝试获取彼此拥有的锁

如何破除死锁

破除死锁其实就是破除上述的四个基本特征 (任意一个条件打破, 死锁就被破除)

对于 synchronized

互斥使用 / 不可抢占 / 请求和保持 都是 synchronized 的基本特征
因此我们只能从 “循环等待” (也就是代码逻辑)下手

最常用的一种死锁阻止策略就是 “锁排序”. 假设有 N 个线程尝试获取 M 把锁, 可以针对 M 把锁进行编号 (1, 2, 3, … , M ), N 个线程尝试获取锁的时候, 都按照编号, 由小到大的顺序来获取锁, 就可以避免环路等待

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值