目录
定义
当线程 A 持有独占锁a,并尝试去获取独占锁 b 的同时,线程 B 持有独占锁 b,并尝试获取独占锁 a 的情况下,就会发生 AB 两个线程由于互相持有对方需要的锁,而发生的阻塞现象,我们称为死锁。
死锁、饥饿、死循环
什么时候产生死锁
模拟死锁
死锁是指多个进程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进
class Test implements Runnable {
boolean flag;
String obj1="1";//必须是可引用的对象 int obj1=1不行
String obj2="2";//由此发现不同Test对象的obj1和obj2其实是同一个,这是由于String常量池的特殊性,一般不会用字符串作为锁对象
Test(boolean flag){
this.flag=flag;
}
@Override
public void run(){
if(flag){
while (true){//while不是必须的,没有while的话多运行几次就死锁了
synchronized(obj1){
System.out.println("true thread have obj1");
synchronized(obj2){
System.out.println("true thread have obj2");
}
}
}
}
else{
while (true){
synchronized(obj2){
System.out.println("false thread have obj2");
synchronized(obj1){
System.out.println("false thread have obj1");
}
}
}
}
}
public static void main(String args[])
{
Thread t1=new Thread(new Test(true));
Thread t2=new Thread(new Test(false));
t1.start();
t2.start();
}
}
产生死锁的四个必要条件
-
互斥条件:一个资源每次只能被一个进程使用,即在一段时间内某资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。
-
不可剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能由获得该资源的进程自己来释放(只能是主动释放)。
-
请求与保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源 已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。
-
循环等待条件: 若干进程间形成首尾相接循环等待资源的关系
-
四个条件对应到死锁例子:
synchronized获取锁对象天然具有互斥性
synchronized在不执行完成前就不会释放锁对象
threadA获取obj1时还想要获取obj2
thread1和thread2互相等待
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。
死锁处理策略
预防死锁
由于资源互斥是资源使用的固有特性,如果不互斥就不叫加锁了,这一点无法针对预防。
- 破坏不可剥夺条件
- 破坏请求与保持条件
- 破坏循环等待条件
避免死锁
- 安全序列
-
系统对进程发出每一个系统能够满足的资源申请进行动态检查
-
并根据检查结果决定是否分配资源
-
如果分配后系统可能发生死锁,则不予分配,否则予以分配。
-
这是一种保证系统不进入死锁状态的动态策略
避免和预防的区别
避免是操作系统对进程和进程之间的(对用户程序不加限制)。预防是操作系统对用户程序限制的(限制其申请资源)。