一篇文章带你理清有关死锁的问题

在学习了无锁之后,让我们重新回到锁的世界吧!在众多的应用程序中,使用锁的情况一般要多于无锁。因为对于应用来说,如果业务逻辑很复杂,会极大增加无锁的编程难度。但如果使用锁,我们就不得不对一个新的问题引起重视—死锁。

什么是死锁呢?通俗地说,死锁就是两个或者多个线程相互占用对方需要的资源,而都不进行释放,导致彼此之间相互等待对方释放资源,产生了无限制等待的现象。死锁一旦发生,如果没有外力介入,这种等待将永远存在,从而对程序产生严重的影响。

用来描述死锁问题的一个有名的场景是哲学家就餐问题,如图4.3所示。哲学家就餐问题可以这样表述,假设有五位哲学家围坐在一张圆桌旁,做以下两件事情之一:吃饭和思考。吃东西的时候,他们就停止思考,思考的时候也停止吃东西。餐桌中间有一大碗意大利面,每两个哲学家之间有一只餐叉。因为用一只餐叉很难吃到意大利面,所以假设哲学家必须用两只餐叉吃东西。他们只能使用自己左右手边的那两只餐叉。哲学家就餐问题有时也用米饭和筷子而不是意大利面和餐叉来描述,因为很明显,吃米饭必须用两只筷子。

哲学家从来不交谈,这就很危险,可能产生死锁,每个哲学家都拿着左手的餐叉,永远都在等右边的餐叉(或者相反)。

在这里插入图片描述
最简单的情况就是只有两个哲学家,假设是A和B,桌面也只有两个叉子。A左手拿着其中一只叉子,B也一样。这样他们的右手等待对方的叉子,并且这种等待会一直持续,从而导致程序永远无法正常执行。

下面用一个简单的例子来模拟这个过程。

在这里插入图片描述
在这里插入图片描述
上述代码模拟了两个哲学家互相等待对方的叉子。哲学家A先占用叉子1,哲学家B占用叉子2,接着他们就相互等待,都没有办法同时获得两只叉子用餐。

在实际环境中,遇到了这种情况,通常的表现就是相关的进程不再工作,并且CPU占用率为0(因为死锁的线程不占用CPU),不过这种表面现象只能用来猜测问题。如果想要确认问题,还需要使用JDK提供的一套专业工具。

首先,我们可以使用jps命令得到Java进程的进程ID,接着使用jstack命令得到线程的线程堆栈

在这里插入图片描述
在这里插入图片描述
上面显示了jstack的部分输出。可以看到,哲学家A和哲学家B两个线程发生了死锁。并且在最后,可以看到两者相互等待的锁的ID。同时,死锁的两个线程均处于BLOCK状态。

如果想避免死锁,除使用无锁的函数之外,还有一种有效的做法是使用第3章介绍的重入锁,通过重入锁的中断或者限时等待可以有效规避死锁带来的问题。大家可以回顾一下相关内容。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值