多线程系列六之死锁

多线程系列六之死锁

提示:本文主要讲述了死锁的三种典型情况

一、什么是死锁

1.死锁在程序猿开发环境中十分影响程序猿幸福感的一个问题,因为死锁的出现十分隐蔽,我们可能会感知不到,从而出现死锁。

2.死锁:死锁是指两个或更多的事物在同一资源的相互占用,并尝试获取对方的资源。

当很多进程因资源竞争而造成的一种僵局(都在互相等待对方释放锁),若没有外力的作用,这些进程都将处在等待之中。

二、死锁的三种典型

1.一个线程一把锁连续加锁两次

在这里插入图片描述

1.此时代码并没有报错,说明在Java中一个线程 一把锁synchronized可以连续加锁两次
2.另外Java中ReentrantLock也可以连续加锁
3.对于可以连续加锁两次的锁,我们称之为可重入锁。

2.两个线程两把锁

此时提供一个场景:
t1 和 t2 两个线程 他们分别有自己的锁locker1 和 locker2,两把线程都尝试获取对方的锁。
这个时候就会出现死锁。
在这里插入图片描述
运行结果:
在这里插入图片描述

1.此时没有打印任何日志,说明t1 和 t2线程都没有获取到对方的锁,发生了死锁
2.可以通过jconsole观察此时线程的情况。

在这里插入图片描述

3.M个线程N把锁

多个线程多把锁的最典型例子就是哲学家就餐问题

1.假设此时有五位哲学家相当于五个线程。
五个筷子相当于五把锁
2.哲学家有两种状态
第一种状态就是思考状态相当于阻塞等待状态
第二种状态就是拿起筷子吃饭阶段,此时相当于线程的执行阶段,执行阶段需要获取到哲学家左手和右手的筷子。
3.如果每个哲学家都拿起右手边的筷子,那么五个线程都会进入死锁阻塞等待。

如图所示
在这里插入图片描述
解决方案

1.右手拿编号小的,左手拿编号大的,从编号小的筷子开始
2.此时最上面那位哲学家不符合要求就会进入阻塞等待
3.因此最右边那位哲学家符合要求,拿到了两个筷子 开始执行,然后依次顺时针进行。
4.到了最上面那位科学家后,他身边的两把锁都已经释放,再拿起两边的筷子,执行任务即可 。

三、可重入与不可重入

1.在Java当中synchronized锁和ReentranLock锁都可以连续加锁两次。这个时候我们称这个锁是可重入锁。
在这里插入图片描述
2.在Java当中无法演示不可重入锁,但是并不意味着其他语言也是可重入的,例如在C++、Python、操作系统原生的加锁的API都是不可重入的。
我们把这种锁称为不可重入锁。

四、死锁的必要条件

1.互斥使用

两个线程都尝试针对同一个对象加锁,线程1获取到锁后,线程2只能阻塞等待。
这也是锁的基本特性

2.不可抢占

线程1获取到锁后,必须是线程1主动释放锁,线程2不能强行获取到锁

3.请求和保持

线程1获取到锁A后,还可以再次尝试获取到锁B,此时锁A还是保持的,不会因为获取到锁B后就把锁A释放了

4.循环等待

线程1尝试获取到锁A和锁B,线程2尝试获取到锁B和锁A
线程1获取锁B的时候只能等待线程2释放锁B
线程2获取锁A的时候只能等待线程1释放锁A


对于上述所说的四点,上面三点都是锁的基本特性,无法改变的。

五、破除死锁

死锁是一个十分影响开发事情的问题,那么如何破除死锁呢?????

由于3点都是锁的基本特性,因此只能从循环等待出发来打破锁的必要条件,这样也就破除了死锁。

办法:可以结合哲学家就餐问题!!!!
多个线程多个锁,给每把锁加上编号0,1,2,3,4,5…,然后按照固定顺序,比如从小到大顺序来加锁,任意线程任意把锁,让线程都遵循这个循环,此时循环等待自然破除,也就破除了死锁。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值