目录
一.为什么会产生死锁?
二.死锁产生的几个场景
一个线程一把锁的情况
关于可重入和不可重入锁的简单举例
两个线程两把锁的情况
多线程多把锁
如何解决死锁
一.为什么会产生死锁?
简单来说,就是进程加锁之后,没有被解锁而处于一直等待的状态
二.死锁产生的几个场景
一个线程一把锁的情况
如果单个线程被连续加锁两次及以上,成为了不可重入锁,那么该线程就造成了死锁(一般的synchronized是可重入锁,不会造成死锁)
关于可重入和不可重入锁的简单举例
public class syn{
public synchronized void do1(){
System.out.println("执行1");
do2();
}
public synchronized void do2(){
System.out.println("执行2");
}
}
如果是不可重入锁,那么我们在执行完输出语句"执行1"之后,因为锁是任然在do1手中,没有释放,那么我们是不能执行do2(),这个语句的
但是如果是可重入锁,那么我们就能直接获取do2的锁,然后执行do2操作
两个线程两把锁的情况
线程一等待着线程二给自己释放锁,线程二等待着线程一给自己释放锁
多线程多把锁
经典案例:哲学家吃面
总所周知,一般人吃面是需要两根筷子(用手抓就算了吧)
但是这里有五个哲学家(五把锁)对应着五个筷子(五个解锁)
如果出现一种比较极端的情况
大家都同时拿自己左手或者右手的筷子(同时都获取了一把锁)
那大家都吃不了(都解锁不了)
所以总结一下,造成死锁的四个条件
1.互斥使用.锁A被线程1占用,线程2就用不了
2.不可抢占.锁A被线程1占用,线程2不能把锁A抢过来, 除非线程1主动释放锁
3.请求和保持.有多把锁,线程1拿到锁A后,不想释放锁A,还想拿到一个锁B
4.循环等待.线程1 等待 线程2释放锁,线程2 要释放锁得等待线程3 来释放锁,线程3 释放锁得等待线程1 释放锁
如何解决死锁
一句话
破坏上诉四个条件的任意一个即可
但是条件一和条件二是锁的基本特性,没法改
条件三的话只要释放锁就行,但是在大多数场景下没办法直接释放
所以一般来说
我们都是破坏循环条件
对于上面的哲学家吃面的问题,我们就可以对筷子(锁)进行编号,控制哲学家们拿筷子的顺序,就能解决死锁
教科书上一般采用银行家算法,但是现实中基本不太实用,有兴趣的同学自行了解本文不多赘述