死锁是什么?产生死锁的原因?如何避免死锁?
死锁是什么?
死锁是指两个或两个以上的进程(线程)在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程(线程)称为死锁进程(线程)。
- 打个比方:假设有甲和乙两个进程(线程),完成任务都需要A和B两个资源,现在甲占有A资源请求B资源,而乙占有B资源请求A资源,两个都请求另一个资源而不肯释放自己占有的资源,于是就这样无限僵持,这就形成死锁,这也是死锁的一种情况。
死锁代码
public class DeadLock {
public static void main(String[] args) {
Object o1 = new Object();//资源o1
Object o2 = new Object();//资源o2
//t1和t2两个线程共享o1,o2,即t1和t2两个线程完成任务都需要资源o1,o2
Thread t1 = new MyThread1(o1,o2);
Thread t2 = new MyThread2(o1,o2);
t1.start();//启动线程
t2.start();
}
}
class MyThread1 extends Thread{
Object o1;
Object o2;
public MyThread1(Object o1, Object o2) {
this.o1 = o1;
this.o2 = o2;
}
public void run(){
synchronized (o1){//表示t1线程占有了资源o1
try {
Thread.sleep(1000);//让线程睡眠一段时间是为了确保另一个线程肯定能占有其他资源, 让死锁100%发生。
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o2){/*一秒之后t1线程想请求资源o2,但此时资源o2已经被t2线程占有,t1线 程没法获取到资源o2,t1线程卡在这,同时也不释放自己占有的资源 o1,同理t2线程也想请求资源o1,但o1资源已被t1占有,没法获取,于 是也卡在这里,这样就造成了两个线程之间的死锁。
*/
}
}
}
}
class MyThread2 extends Thread{
Object o1;
Object o2;
public MyThread2(Object o1, Object o2) {
this.o1 = o1;
this.o2 = o2;
}
public void run(){
synchronized (o2){//表示t2线程占有了资源o2
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (o1){
}
}
}
}
产生死锁的原因
1.竞争不可抢占资源引起死锁
也就是上面那种情况,都在等待对方占有的不可抢占的资源。
2.竞争可消耗资源引起死锁
有p1,p2,p3三个进程,p1向p2发送消息并接受p3发送的消息,p2向p3发送消息并接受p1发送的消息,p3向p1发送消息并接受p2发送的消息,如果设置是先接到消息后发送消息,则所有的消息都不能发送,这就造成死锁。
3.进程推进顺序不当引起死锁
有进程p1,p2,都需要资源A,B,本来可以p1运行A --> p1运行B --> p2运行A --> p2运行B,但是顺序换了,p1运行A时p2运行B,容易发生第一种死锁。互相抢占资源。
资源的分类
系统中有许多不同类型的资源,需要采用互斥访问方法并且不可被抢占的资源,就是临界资源。
1.按使用次数分类
(1)可重用性资源
每一个可重用资源中的单元只能分配给一个进程使用,不允许多个进程共享。
进程是用资源顺序:1 请求资源,如果请求失败进程阻塞或循环等待。2 使用资源。3释放资源。
系统中的可重用资源数目都是相对固定的程序运行时不能增加或删除。
(2)消耗性资源
他是临时资源,有进程运行动态创建和消耗的,每一类消耗性资源单元数目都是不断变化的,通常在生产者进程中创建,在消费者进程中消耗。
2.按能否抢占资源分类
(1)可抢占资源
CPU,主存等可以共享的资源。
(2)不可抢占资源
打印机,光驱等不可共享的资源。
产生死锁的四个必要条件
- **互斥使用:**即当资源被一个线程使用(占有)时,别的线程不能使用
- **不可抢占:**资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放。
- **请求和保持:**即当资源请求者在请求其他的资源的同时保持对原有资源的占有。
- **循环等待:**即存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路。
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。
如何避免死锁
我们只要破坏产生死锁的四个条件中的其中一个就可以了。
破坏互斥条件
这个条件我们没有办法破坏,因为我们用锁本来就是想让他们互斥的(临界资源需要互斥访问)。
破坏请求与保持条件
一次性申请所有的资源。
破坏不剥夺条件
占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源。
破坏循环等待条件
靠按序申请资源来预防。按某一顺序申请资源,释放资源则反序释放。破坏循环等待条件。
参考博文:https://blog.csdn.net/DT_Zhangshuo/article/details/53334030