死锁
1.1 死锁的概念
当两个或多个线程需要相同资源,如果线程获取不到其他资源,就会进入阻塞状态,程序就会挂起.
1.2 死锁的前提
- 多线程
- 获取相同资源
1.3 死锁的条件
- 互斥条件 : 进程对于所分配的资源具有排它性 ,即一个资源只能被一个进程占用,直到被该进程释放.
- 请求和保持条件: 一个进程因请求被占用资源而发生阻塞时,对已获取的资源保持不放.
- 不剥夺条件:任何一个资源在没有被该进程释放时,任何其他进程都无法对其剥夺占用
- 循环等待条件:当发生死锁时,所等待进程必定会形成一个闭环(类似于死循环),造成永久阻塞
1.4 代码实现
思路
1).:创建两个锁对象,用static修饰(即只创建一次对象)
2).:在run方法中嵌套同步
3).:分别启动两个线程运行if中代码
上代码:
//线程实现类代码块
private static Object obj1 = new Object();
private static Object obj2 = new Object();
boolean b = false;
public DieSlock(boolean b){
this.b = b;
}
@Override
public void run() {
while (true){
if (b){
//当同步嵌套时,可能会发生死锁
synchronized (obj1){
System.out.println("true==>"+obj1);
synchronized (obj2){
System.out.println("true==>"+obj2);
}
}
}else {
synchronized (obj2) {
System.out.println("false==>" + obj2);
synchronized (obj1) {
System.out.println("false==>" + obj1);
}
}
}
}
}
测试代码块
public static void main(String[] args) {
Thread thread = new Thread(new DieSlock(true));
Thread thread2 = new Thread(new DieSlock(false));
thread.start();
thread2.start();
}
1.5 如何避免死锁
- 加锁顺序: 当多个线程需要相同的一些锁,但是按照不同顺序加锁,死锁就很容易发生.
如果能够确保所有的线程都是按照相同的顺序获得锁,那么死锁就不会发生.- 加锁实现 尝试获取锁的时候加一个超时时间,这也就意味着在尝试获取锁的过程中若超过了这个时限该线程则放弃对该锁请求。若一个线程没有在给定的时限内成功获得所有需要的锁,则会进行回退并释放所有已经获得的锁,然后等待一段随机的时间再重试。这段随机的等待时间让其它线程有机会尝试获取相同的这些锁,并且让该应用在没有获得锁的时候可以继续运行(译者注:加锁超时后可以先继续运行干点其它事情,再回头来重复之前加锁的逻辑)。