死锁是如何产生的
引言
本节介绍一个和同步所相关的知识点死锁。下面从3点来介绍死锁。
第一点什么是死锁?第二点死锁是如何产生的?第三点编写一个死锁示例。
什么是死锁?
首先来看第一点,什么是死锁?死锁是指两个或两个以上的线程,在执行过程中,由于竞争资源或者是由于彼此通信而造成的一种阻塞现象,若无外力作用,他们都将无法推进下去。此时称系统处于死锁状态或系统产生的死锁,这些永远在互相等待的线程称为死锁线程。
简而言之就是两个或两个以上的线程争夺彼此的锁造成阻塞,程序永远处于阻塞状态。
这就好比一个女孩一个男孩,女孩手上有男孩想要的魔方,男孩手上有女孩想要的棒棒糖,然后女孩说我想要棒棒糖,接着男孩说我想要魔方,于是女孩对男孩说,你把棒棒糖给我,我就给你魔方。这时男孩也对女孩说,你把魔方给我,我就给你棒棒糖,于是他们谁都不让谁僵持住,这个过程就和死锁很像。
下面我们把男孩女孩换成线程,看看线程a持有a锁,想要b锁,线程b持有b锁下想要a锁,
他们互不相让,僵持住,形成了死锁局面。
死锁是如何产生的?
第一点介绍完了。我们再来看第二点,死锁是如何产生的?
死锁的产生主要有4个条件,
第一个条件是两个或两个以上的线程,
第二个条件是两个或两个以上的锁。
第三个条件是两个或两个以上的线程持有不同所。
第四个条件是持有不同锁的线程争夺对方的锁。
编写一个死锁事例
下面我们根据死锁的产生条件,来编写一个死锁事例,按照这4个条件一步一步编写。
第一个条件
首先是第一个条件,两个或两个以上的线程定义两个类,
分别是locka和lockb然后继承thread类,于是线程a和线程b两个线程就准备好了。
第二个条件
第一个条件应满足,再来看第二个条件,两个或两个以上的锁。分别在locka和lockb两个类里面边写一个静态同步方法,printera和printb.于是同步锁locka, lockb两个锁就准备好了。接着分别在两个方法里面输出a和b这个输出主要是用于观察方法是否被正常调用。在输出之前,我们使当前线程休眠一秒钟,此步骤为的是让线程不要太快执行完,待会还要在下面调用对方的方法去争夺对方的锁。
第三个条件
第二个条件以满足,再来看看第三个条件,两个或两个以上的线程持有不同的锁,很简单,直接重写run方法,然后在run方法里面分别调用printa和printb即可。
于是线程a持有锁就是locka.class,因为是静态同步方法,所以锁的类型就是自身类名点class,同样的线程lockb就只有同步锁lockb.class,
现在两个线程已经持有了不同的数。第三个条件已满足。
第四个条件
再来看看第四个条件,只有不同锁的线程去争夺对方的锁,我们只需在printA A方法里面去调用lockB .printB方法,在printAb方法里面去调用printA .printa方法即可,如此一来线程a就去争夺lockb的锁,线程b就去争夺locka的锁,最后1个条件也已经满足了,现在4个条件全部满足。
结果
下面来启动这两个线程,首先将线程创建出来,然后启动他们。
接下来我们去看看执行结果。从运行结果来看,两个线程分别在打印了a和b之后,进入相互争夺锁的过程,双方僵持住形成了死锁程序,想要停下来需手动关闭,也就是借助外力。
总结
最后来总结一下本节的内容。本节演示了死锁,死锁的定义在这里就不再赘述了。希望大家在以后使用同步的时候避免死锁。
附录:
笔记完整文本:
本节介绍一个和同步所相关的知识点死锁。下面从3点来介绍死锁。第一点什么是死锁?第二点死锁是如何产生的?第三点编写一个死锁示例。首先来看第一点,什么是死锁?死锁是指两个或两个以上的线程,在执行过程中,由于竞争资源或者是由于彼此通信而造成的一种阻塞现象,若无外力作用,他们都将无法推进下去。此时称系统处于死锁状态或系统产生的死锁,这些永远在互相等待的线程称为死锁县城。简而言之就是两个或两个以上的线程争夺彼此的所造成阻塞,程序永远处于阻塞状态。 这就好比一个女孩一个男孩,女孩手上有男孩想要的魔方,男孩手上有女孩想要的棒棒糖,然后女孩说我想要棒棒糖,接着男孩说我想要魔方,于是女孩对男孩说,你把棒棒糖给我,我就给你魔方。这时男孩也对女孩说,你把魔方给我,我就给你棒棒糖,于是他们谁都不让谁僵持住,这个过程就和死锁很像。下面我们把男孩女孩换成线程,看看线程a持有a锁,想要b锁,线程b持有b锁下压a锁,他们互不相让,僵持住,形成了死锁局面,第一点介绍完了。我们再来看第二点,死锁是如何产生的? 死锁的产生主要有4个条件,第一个条件是两个或两个以上的线程,第二个条件是两个或两个以上的锁。第三个条件是两个或两个以上的县城持有不同所。第四个条件是只有不同锁的线程争夺对方的锁。下面我们根据词所的产生条件,来编写一个搜索事例,按照这4个条件一步一步编写。首先是第一个条件,两个或两个以上的线程定义两个类,分别是洛克a和look b然后继承Siri的勒,于是线程a和线程b两个线程就准备好了。 第一个条件应满足,再来看第二个条件,两个或两个以上的锁分别在Outlook a和log b两个类里面边写一个静态同步方法,printer a和print的b于是同步锁look a look,b两个锁就准备好了。接着分别在两个方法里面输出a和b这个输出主要是用于观察方法是否被正常调用。在输出之前,我们使当前线程休眠一秒钟,此步骤为的是让县城不要太快执行完,待会还要在下面调用对方的方法去争夺对方的手。第二个条件以满足,再来看看第三个条件,两个或两个以上的线程持有不同勒索,很简单,直接重写run方法,然后在run方法里面分别调用prune的a普润的b即可。 于是线程a持有数就是录a、点class,因为是静态同步方法,所以所的类型就是自身类名点class,同样的线程look AP就只有同步锁log b点class,现在两个县城已经持有了不同的数。第三个条件已满足。再来看看第四个条件,只有不同锁的线程去争夺对方的锁,我们只需在point AA方法里面去调用oc bea点point bea方法,在普润的b方法里面去调用洛克a点普润的a方法即可,如此一来线程a就去争夺look b的锁,线程b就去争夺洛克a的锁,最后1个条件也已经满足了,现在4个条件全部满足。 下面来启动这两个线程,首先将线程创建出来,然后启动他们。接下来我们去看看执行结果。从运行结果来看,两个线程分别在打印了a和b之后,进入相互争夺锁的过程,双方僵持住形成了死锁程序,想要停下来需手动关闭,也就是借助外力。最后来总结一下本节的内容。本节演示了死锁,死锁的定义在这里就不再赘述了。希望大家在以后使用同步的时候避免死锁。