要想模拟死锁就要知道死锁的产生原因和条件,先看一下死锁的产生条件
死锁产生的必要条件:
1、 互斥使用: 既当资源被一个线程使用(占有)时,别的线程不能使用
2、 不可抢占: 资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有着主动释放
3、 请求和保持: 即当资源请求者在请求其他的资源的同时保持对原有资源的占有
4、 循环等待: 既当存在一个等待循环序列:p1要p2的资源,p2要p1的资源。这就形成了一个等待环路
概念分析:
如图:
模仿现实生活中的生产者-消费者问题,消费者有资金但是没有货源,而生产者有货源却没有资金。
有人会说生产者给消费者提供货源,消费者为生产者提供资金不就不会出现死锁了吗,答案是那肯定是呀,但是问题出在哪里?
死锁产生的必要条件有一个不满足就不会发生死锁
用上图来解释一下:
互斥使用 生产者占有了资金,但是却没有货源。消费者占有货源,而没有资金
请求和保持 消费者在需要货源时,不愿意先提供资金给生产者。而生产者在没获得资金时也不愿意先发货给生产者
例如,你在某宝买东西要求货到付款,而卖家要求你先付款后发货,到最后这笔交易就不会发生
不可抢占:生产者不能把消费者的货源给抢了,同理消费者也不能把生产者的资金抢了。
循环等待 生产者要消费者的货源,消费者要生产者的资金
死锁使我们在开发中一定一定要避免的,但是我们要明白它的原理,在面试的时候用的特别多
用代码演示死锁:
public class Test_死锁案例 {
//创建两个锁对象,模拟资金和货源
public static Object o1 = new Object();
public static Object o2 = new Object();
public static void main(String[] args) {
//创建线程1
new Thread(new Runnable() {
@Override
public void run() {
synchronized (o1) {
System.out.println(Thread.currentThread().getName()+"占用资源1,请求资源2");
try {
//休眠,让另一个线程抢占cpu,加大产生死锁的概率
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (o2) {
System.out.println(Thread.currentThread().getName()+"占用资源2,请求资源1");
}
}
}
}).start();
//创建线程2
new Thread(new Runnable() {
@Override
public void run() {
synchronized (o2) {
System.out.println(Thread.currentThread().getName()+"占用资源2,请求资源1");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
synchronized (o1) {
System.out.println(Thread.currentThread().getName()+"占用资源1,请求资源2");
}
}
}
}).start();
}
}
/*死锁发生的原因:当两个线程被执行时,假如线程1优先获得了cpu的使用权,此时它会获得o1的锁对象。
* 获得锁对象后,它休息了1秒钟,此时线程2夺取到了cpu的使用权,线程2获得了o2的锁对象,在接下来的
* 执行中,不管哪个线程获得了cpu的使用权,它需要的锁对象都被另一个线程所占有。因此出现了死锁。
*
* */