死锁的成因以及解决方案

🎈专栏链接:多线程相关知识详解

目录

一.什么是死锁以及死锁的成因

Ⅰ.一个线程一把锁

Ⅱ.两个线程两把锁

Ⅲ.多个线程多把锁

二.死锁的解决方案


一.什么是死锁以及死锁的成因

死锁是一个线程加上锁了之后,解不开了

在多线程编程中,我们为了防止多线程竞争共享资源而导致数据错乱,都会在操作共享资源之前加上互斥锁,只有成功获得到锁的线程,才能操作共享资源,获取不到锁的线程就只能等待,直到锁被释放。

死锁的成因:

Ⅰ.一个线程一把锁

线程连续加锁两次,如果这个锁是不可重入锁,那必然就是死锁,synchronized是可重入锁,没有这个问题

Ⅱ.两个线程两把锁

当两个线程为了保护两个不同的共享资源而使用了两个互斥锁,那么这两个互斥锁应用不当的时候,可能会造成两个线程都在等待对方释放锁,在没有外力的作用下,这些线程会一直相互等待,就没办法继续运行,这种情况就是发生了死锁。

例如:家里门的钥匙锁车里,而车钥匙锁家里了

Ⅲ.多个线程多把锁

对于该问题有一个典型的例子:哲学家就餐问题

一张桌子,上面有一碗意大利面,和5根分散开来的筷子,桌子旁边坐着5名哲学家

 每个哲学家只做两件事情:

1.思考人生,啥也不干(线程阻塞)

2.吃面条,先拿左手边的筷子,再拿右手边的筷子,吃一会儿放回筷子

啥时候做第一件事啥时候做第二件事都是不确定的(线程随机调度)

在大部分情况这个是不会出现问题的

但是如果当5个哲学家同时要吃面条,拿起了左手边的筷子,就会出现死锁,因为右手边的筷子被其他哲学家拿走了

出现死锁的四个必要条件:

1.互斥使用.锁A被线程1占用,线程2就用不了

2.不可抢占.锁A被线程1占用,线程2不能把锁A抢过来, 除非线程1主动释放锁

3.请求和保持.有多把锁,线程1拿到锁A后,不想释放锁A,还想拿到一个锁B

4.循环等待.线程1 等待 线程2释放锁,线程2 要释放锁得等待线程3 来释放锁,线程3 释放锁得等待线程1 释放锁

二.死锁的解决方案

在上面死锁的四个必要条件当中,第一条和第二条是锁的必要条件 无法改变,

第三条的话,如果需求场景符合获取锁B的时候先释放了锁A那也是可行的,但是这个方法不普适

解决死锁的突破口就在第四条,约定好加锁的顺序,就可以打破循环等待

线程t1的加锁顺序:locker1 , locker2.  线程t2的加锁顺序:locker2 , locker1.   这样就导致了循环等待,如果调整了顺序,就可以避免循环等待

例如:给锁编号,约定加多个锁的时候,必须先加编号小的锁,后加编号大的锁

让这些哲学家约定所获取的两把锁必须先获取编号小的,再获取编号大的(而不是先拿左手的再拿右手的) 

这样子的话,从第一个哲学家开始拿编号小的筷子,直到第5个哲学家,他得先拿编号小的筷子1,才能拿编号大的筷子5,但是筷子1已经被第一个哲学家拿走了,这样的话第5个哲学家就会进入阻塞等待状态,等待第1个哲学家释放锁,这样就不会造成死锁问题

有一个更普适的解决方案 --- "银行家算法"(把所有的资源统一进行统筹分配),但不太适合实际开发

  • 15
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 13
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山涧晴岚.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值