解决方法有:

1、更改为单个锁
2、将锁排序

产生死锁的原因

产生死锁的原因是一个线程在持有一把锁时又去申请另外一把锁,也就是锁嵌套。而另一把锁被另外一个线程持有。

举个广为人知的例子:"哲学家就餐"

假如有两个哲学家坐在一个圆形桌子上,桌子上只有两根筷子,每一个哲学家左手边都会有一根筷子。当哲学家要吃饭时需要先左手拿手筷子,再右手拿上筷子,如图
解决死锁——哲学家就餐
双手拿上筷子后才能吃饭,吃完饭就放下右边筷子、再放下左边筷子。本来俩位老先生都挺斯文的,那晓得两个都饿了,同时拿起了左手边的????,右眼一瞧发现筷子在另一个人手里,这个时候哲学家们就闹矛盾了,扬言要先吃到饭才肯放下手中的筷子。这个时候(两个老先生就都吃不上饭,最终饿死)就产生了死锁。
同样,桌子上有5位哲学家、5根筷子,他们都遵守上面两位泽学家一样的规则来吃饭,如图:
解决死锁——哲学家就餐
这时候就产生了循环等待。
总结出产生死锁的原因有4点必要条件:
1、锁互斥:锁在同一时刻只能被一个线程占用;
2、锁等待:锁在被另外一个线程占用时,当前线程只能等待对方把锁释放掉;
3、嵌套锁:在当前拥有一把锁时,去申请另外一把锁;
4、循环等待锁:如上面五位哲学家,相互等待其左手上的筷子;

要解决死锁的方法就是**上面4种条件中的任意一种,但是1点和2点是锁必备条件,我们无法在上面动手脚,那么就只有3点和4点钟开刀了。

嵌套锁开刀:更改为单个锁

解决办法就是在满足业务的情况下,只定义一把锁,对照上面5位才华横溢的哲学家来说,同一时刻只能有一个哲学家能吃到饭。
缺点:
显然,明明有5根筷子,能有两位哲学家可以同时吃饭,这大大降低了系统的并发性,还会导致锁挣用而产生上下文切换。

循环等待锁开刀:将锁排序

重点介绍这个方法,这个方法的思想有点饶,大家跟紧步伐!!高能预警!!!
开个玩笑,其实一点都不难的:
思考一个问题: 循环等待锁是因为哲学家们左边的筷子是别人右边的筷子,哲学家们总是左手先拿筷子,再去拿右手的筷子。而右手筷子可能已经被另一个哲学家拿了,每个都等待着右手边的筷子被放下,也就产生了循环等待。我们怎么破坏这种形式呢?
答案来了: 让其中一个或多个哲学家原本该拿到左手边的筷子用右手拿,右手边的筷子让左手拿。我们依然回到两个哲学家哪一桌,规定其中一位哲学家左手去拿右手边筷子,右手去拿左手边筷子。此时两个泽学家都饿了,他们左手会同时去抢同一根筷子(因为有一个哲学家左手回去拿右手边的筷子,右手边这根筷子是另外一个左手边的筷子),此时就会有一个没有抢到而进行等待(注意另外一根还在桌子上),然后抢到筷子那个人看到右手要拿的筷子还在桌子上高兴惨lao。
解析: 如上长篇答案,总会有一个哲学家会抢到两根筷子,他吃完了就放下,别人就可以抢了。那么就不存在循环等待了。
具体实现:
我们如何才能让哲学家心肝情愿左手拿右边的筷子呢?那就大家形成约定吧:

将所有筷子进行排序,每两根筷子都会存在一大一小或是相同大小。小的左手拿,大的右手拿。相同大小的一起拿。

对照上面两位哲学家,它们有两根筷子分布在他们左手边,一大一小。从图上看,你应该知道说话那位哲学家(上吧位)的右手会去拿大筷子,左手会去拿小筷子!
解决死锁——哲学家就餐
解决死锁——哲学家就餐
在Java中我们如何统一为锁对象进行排序呢?

  • 进行统一的哈希值计算:System.identityHashCode(Object)

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-12-05
  • 2022-12-23
猜你喜欢
  • 2021-07-09
  • 2021-11-06
  • 2022-12-23
  • 2022-12-23
  • 2021-06-25
  • 2021-12-31
相关资源
相似解决方案