上文锁策略中, 当谈到可重入锁和不可重入锁时, 我们引入了一个 “死锁” 的概念, 当针对一把不可重入锁进行连续两次的加锁行为时, 就会产生死锁.
本文就重点来讲解一下关于死锁的一些知识.
关注收藏, 开始学习吧
在锁策略中, 我们提到过死锁这一概念, 死锁是这样一种情形: 多个线程同时被阻塞, 它们中的一个或者全部都在等待某个资源被释放. 由于线程被无限期地阻塞, 因此程序不可能正常终止.
1. 一个线程, 一把不可重入锁. 该线程针对这个锁连续加锁两次, 就会出现死锁.
这就是我们上文提到的锁策略中的不可重入锁, 带来的死锁, 是因为针对一把不可重入锁, 连续加锁两次所导致的.
2. 两个线程, 两把锁. 这两个线程先分别获取到一把锁, 然后再同时尝试获取对方的锁.
这个场景其实可以通过生活场景来去理解, 就好比你把车钥匙落家里了, 但是家钥匙又落车里了. 如果你想开家门, 就得先开车门. 想开车门, 就得先开家门. 无限循环形成套娃.
3. 有N个线程, 有M把锁. 这几个线程互相获取锁, 也会有几率出现死锁
很经典的 “哲学家就餐问题” 就是用来描述这个情境的.
基于以上的设定, 在大部分情况, 这些哲学家都可以很好地开展工作, 去思考, 去吃面条. 但是如果出现了极端情况, 就会发生死锁.
假设同一时刻, 五个哲学家同时拿起左手边的筷子, 然后再尝试拿右手的筷子, 就会
发现右手的筷子都被占用了. 由于哲学家们互不相让, 这个时候就形成了死锁.
在哲学家就餐问题中, 五个哲学家就相当于五个线程, 五根筷子就相当于五把锁.
在了解死锁出现的几个典型场景后, 请思考一下, 有什么办法能够解决死锁问题呢? 想知道如何解决死锁问题, 我们首先要从根本原因出发, 先明确发生死锁的原因, 明白死锁产生的必要条件是什么.
死锁产生的四个必要条件:
当上述四个条件都成立的时候, 便形成死锁. 四个条件缺一不可, 只要能够破坏其中的任意一个条件, 都可以避免出现死锁. 对于我们来说, 其中最容易破坏的就是 “循环等待”.
破坏 “循环等待” 是我们解决死锁问题的关键, 而如何具体的解决死锁问题, 实际的方法有很多, 学过操作系统的读者, 应该都听说过 “银行家算法”, 该算法其实就是用来解决死锁问题的, 不过对于我们来讲, 不够接地气.
在这里, 我们介绍一个, 更加简单, 也可以高效的解决死锁问题的方法 ---- 锁排序.
锁排序就是对锁来进行编号, 并且规定好加锁的顺序, 比如约定, 每个线程如果要获取多把锁, 必须先获取编号小的锁, 后获取编号大的锁. 只要所有线程加锁都严格遵守上述规则, 那么就不会出现 “循环等待” 的这种情况.
在上述哲学家就餐问题中, 我们只要约定好, 从一到五, 给每个筷子都设置一个编号, 所有哲学家, 拿筷子时先拿编号小的筷子, 再拿编号大的筷子, 这样就不会出现我们说的那种极端情况了.
✨ 本文主要讲解了一些死锁的概念, 重点介绍了死锁的几种典型场景, 以及死锁产生的几个必要条件, 并且讲述了如何去解决死锁问题.
✨ 想了解更多的多线程知识, 可以收藏一下本人的多线程学习专栏, 里面会持续更新本人的学习记录, 跟随我一起不断学习.
✨ 感谢你们的耐心阅读, 博主本人也是一名学生, 也还有需要很多学习的东西. 写这篇文章是以本人所学内容为基础, 日后也会不断更新自己的学习记录, 我们一起努力进步, 变得优秀, 小小菜鸟, 也能有大大梦想, 关注我, 一起学习.
再次感谢你们的阅读, 你们的鼓励是我创作的最大动力!!!!!