死锁是什么?什么情况下会产生死锁?我们该如何解决?

时间:2021-02-15 01:20:49

目录

1.一个线程对应一把锁

2.两个线程对应两把锁

3.多个线程对应多把锁

4.产生死锁的四个必要条件

5.如何破解死锁?


1.一个线程对应一把锁

     一个线程对锁对象加锁后,忘记解锁,等自己再次需要对该锁对象加锁时(忘记是自己加锁的),发现锁已经被占用,于是就一直阻塞等待,但是自己加的锁必须由自己释放,这就会出现死锁的状态.,就是没有人来解锁,线程一直阻塞等待.

举个例子:

        我去商场买衣服,在试衣间换衣服的时候把门锁了,换完不知道怎么的我就从试衣间出来了,而且我忘记了是自己上的锁,等我挑好衣服再次进试衣间发现进不去了,以为有人就一直等待,但是这个时候试衣间里没有人,我在门外也解不了锁,这时候就是死锁的状态,没有人来解锁.我就一直阻塞等待.

注:synchronized锁是可重入锁(连续对同一锁对象加锁两次不会出现死锁状态),不会出现这种状态.


2.两个线程对应两把锁

     线程A对锁B进行加锁,线程B对锁A进行加锁.当线程A尝试对锁A进行加锁的时候,发现锁A被占用,所以阻塞等待(此时锁B还未释放),而线程B尝试对锁B进行加锁发现锁B被占用,又阻塞等待(此时锁A还未释放),这样线程A就会等线程B把锁A释放,线程B就会等线程A把锁B释放,两个一起阻塞等待,这时候也没有人去解锁,也产生了死锁的状态.

举个例子:

       很经典一个例子就是你的车钥匙在家里,大门钥匙在车里,要想进家里就要打开车门,但是打开车门又要打开你家大门.这样门和车门都打不开,这就出现死锁状态.


3.多个线程对应多把锁

     多个线程中的每个线程都在阻塞等待对应已经被占用的锁释放,而每个线程自己占用的锁都还未释放(别的线程也许在阻塞等待它们把自己占用的锁释放).线程A占用A锁,线程B占用B锁,线程C占用C锁. 线程C要对锁A加锁解锁后才能释放锁C,但是锁A被占用,它就一直阻塞等待锁A;而线程A要对锁B加锁解锁后才能释放锁A,但是锁B也被占用,它就一直阻塞等待锁B;线程B要对锁C加锁解锁后才能释放锁B,但是锁C也被占用,它就一直阻塞等待锁C.这样线程A等待线程B将锁B释放,线程B等待线程C将锁C释放,线程C等待线程A将锁A释放.它们一直阻塞等待,没人解锁,出现死锁状态.

举个例子

        三个人(甲,乙,丙)同吃一碗面,桌上有三根筷子(编号分别为1,2,3),甲拿到1号筷子,还不能吃到面,因为它只拿了一根筷子,这时候乙拿到了2号筷子,也不能吃到面,突然丙抢到了3号筷子,那你觉得它们还能吃到面吗?每个人都只拿到了一根筷子,且它们都在等旁边的放下筷子好去抢离自己最近的筷子.有了一双筷子它们自己吃了面才能将一双筷子都放回桌子上.这样死等谁都吃不到面,所以就出现死锁的状态.


4.产生死锁的四个必要条件

     ① 不可抢占: 哪个线程加的锁只能由它自己进行释放,其它线程不能抢占.

     ② 互斥使用: 一个线程先抢到锁之后,其它线程只能阻塞等待.

     ③ 请求和保持: 一个线程占用一个锁的情况下,还要抢另一个锁.

     ④ 循环等待: 线程间的解锁都互相依赖,就像上述中甲乙丙三个人要吃到面放下筷子,三个人循环依赖的关系.

注:四个条件只有循环等待最好破解.


5.如何破解死锁?

     很简单,直接规定加锁的顺序,线程只能先加序号小的锁,再加序号大的锁,在甲乙丙的例子中,也就是甲先对1号筷子进行加锁,乙对2号筷子加锁,丙的两边1号筷子序号最小,它尝试对1号筷子加锁,但是1号筷子已经被占用,而乙抢了2号筷子之后,就能直接抢到3号筷子,吃完面放下筷子,然后甲就能对2号筷子进行加锁,也吃完面放下筷子,最后丙就可以先对1号加锁,再对3号筷子进行加锁,吃完面也放下筷子.它们的位置如图:

死锁是什么?什么情况下会产生死锁?我们该如何解决?


分享完毕~