死锁,哲学家就餐问题

在上一篇中,大体介绍了在线程中常见的锁策略和锁模式。http://t.csdnimg.cn/JlbgC 文章在末尾的时候在可重入锁和不可重入锁的时候,讲到了死锁,这篇文章中我们着重讲一下死锁. (才不是我馋CSDN的1500流量卷);

死锁的情况

在什么情况下会出现死锁呢
不可重入锁在本文开始那篇文章描述很详细了,这里不过多叙述

  1. 一个线程一把锁,但是这把锁是不可重入锁,针对这把锁加锁两次就会出现死锁。
  2. 两个线程,两把锁,两个线程分别获取到一把锁之后,互相尝试获取对方的锁
  3. N个线程,M把锁。

这里针对第二点,我们形象举例一下,就比如 我有一把钥匙锁在了车里面,车钥匙呢又锁在了房子里,我想要打开车就需要房子的钥匙但是房子的钥匙又在车里,这样就是一种很典型的死锁问题。

同时针对上诉问题的第三个点,在操作系统中有一个很著名的问题叫  哲学家就餐问题 

哲学家就餐问题

哲学家就餐问题就讲述了关于N个线程M把锁的情况 
这里我们借用一下汤神的滑稽老铁

假设此时有5个哲学家,每一个哲学家面前都有一根筷子,每个哲学家呢,要做的事情有两件事

  1. 思考人生,此时哲学家会放下筷子
  2. 吃面,此时的哲学家会先拿起左手的筷子,然后在拿起右手的筷子,最后夹面吃。

此外针对于哲学家呢 还有以下的设定

  • 每个哲学家呢,什么时候吃面,什么时候放下筷子,处于一种随机不确定状态的。
  • 每个哲学家都非常的固执,在没有吃到面条之前,要是他的筷子被别人使用,就会进行一个阻塞等待,并且等待的过程中也不会放下手中的筷子。

在有了上述的设定之后,我们不难发现,上述系统在运转上大部分的时间其实都是没什么问题的,大不了阻塞等待一会就能恢复系统原有秩序,但是有可能会出现一种特殊情况

上述的五个哲学家在某一个时刻,同时有了吃面条的想法,此时他们同时拿起了左手的筷子,他们想拿右手筷子的时候,筷子已经被其他哲学家拿走了,但是他们此时并不会放下手中的筷子,而是进行一个阻塞等待,等待过程中,因为每个筷子都被拿走了,所以也无法等待出一个确切的结果,这也就会造成我们常见的计算机的一个死锁问题

上述问题就是很好的一个比喻,五个哲学家就表示五个线程,同时五根筷子就表示五个锁。

我们如何避免上述的情况呢,这里我们讲一下出现死锁的四个必要情况,只有当以下四种情况都集齐的时候死锁才有可能发生

  1. 互斥使用:一个线程获取到一把锁之后,其他的线程不能获取这把锁了。
  2. 不可抢占:一个锁只能有持有的线程所释放,不能被其他线程中途给进行劫持。
  3. 请求和保持:当一个线程持有一把锁的时候,去获取另外锁的时候,不会丢失对一把锁的获取关系。
  4. 循环等待:一把线程想要获取一个已经被占有的锁的时候,需要等待另一个线程将该锁进行释放。

只有集齐上述四种条件之后,才有可能会出现死锁问题,所以我们只要破坏其中一个条件就可以解决死锁问题了。 但不难看出,上述代码中前2个条件都是操作系统中锁的基本设定,所以不太可能破坏前2个条件,除非修改内核代码(这里我也不太了解),那我们主要是就是把重心放在了破坏第三或者第四个条件上面,但是呢,一般在调整第三个条件的时候,往往会改变项目结构。所以我们可以重点关注怎么解决第4个条件。

学过操作系统的同学可以知道,在操作系统中,有一个很著名的算法,银行家算法,但是银行家算法实现比较复杂(我也不清楚具体实现),可能在实现过程中会引入更多的bug,所以这里我们采用更简单的算法。

这里我们规定针对锁进行编号,并且规定加锁顺序,同时这里我们规定

  • 每个线程如果要获取多把锁,必须先获取编号小的锁,在获取编号大的锁。

所有加锁的顺序都严格按照上述顺序,就一定不会出现循环等待的情况。

还是咱们的滑稽老铁,只不过这一次的哲学家和筷子,我们都按照上述的约定来对他进行了一个编号。

同理当还是几位哲学家同时想吃饭的时候,当第2位哲学家拿起第一根筷子,第三位哲学家拿起第二根筷子,第四位哲学家拿起第三筷子,第五位哲学家拿起了第四根筷子之后,在原本没有编号的情况下,第一位哲学家应该拿去第五根筷子的,但是我们有了上述的规定,只能重小编号的开始拿,第一位哲学家先拿右手的编号为1的筷子,但筷子一又被占用了,所以。此时他会进行阻塞等待的状态,在这样的过程中,死锁问题就一下迎刃而解了。

JAVA中synchronized 锁策略

在了解到死锁和前一篇文章中的锁策略之后,JAVA中的synchronized是一把怎么样的锁呢。这就就不得不说到开发jvm的开发者的神级优化了。

  • 既是悲观锁,又是乐观锁(自适应)
  • 既是重量级锁,也是轻量级锁(重量级锁是基于系统的互拆锁实现的,轻量级锁是基于自旋锁实现的)
  • 是非公平锁(等待过程中不会先来后到,而是有均等的概率来获取这把锁)
  • 是一把可重入锁
  • 不是读写锁

后面的锁升级策略就在写一篇博客单独讲了也包括后面的CAS

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值