某个线程T1锁住资源A,需要再拿到资源B的锁才能执行完成,而另一个线程T2锁住了资源B,需要再拿到资源A的锁才能完成,但是T2不把资源B的锁给T1,T1线程就无法继续往下执行,T1不把资源A给T2,T2的任务也无法完成,所以就线程相互僵持的现象,这种现象称之为死锁。
代码示例如下:
package com.trs.thread;
/**
* 死锁示例
* @author xiayunan
* @date 2018年7月14日
*
*/
public class TestDeadLock2 {
public static void main(String[] args) {
Thread t1 = new Thread(new MyThread5(0));
Thread t2 = new Thread(new MyThread5(1));
t1.start();
t2.start();
}
}
class MyThread5 implements Runnable{
private static Object o1 = new Object();
private static Object o2 = new Object();
private int flag;
public MyThread5(int flag) {
this.flag = flag;
}
@Override
public void run() {
if(flag==0){
synchronized (o1) {
System.out.println(Thread.currentThread().getName()+"锁住了o1");
synchronized (o2) {
System.out.println(Thread.currentThread().getName()+"执行结束");
}
}
}else{
synchronized (o2) {
System.out.println(Thread.currentThread().getName()+"锁住了o2");
synchronized (o1) {
System.out.println(Thread.currentThread().getName()+"执行结束");
}
}
}
}
}
运行结果如下:
从结果中可以看出,程序处于僵持状态,一直没有再继续执行。
那我们应该如何避免死锁呢?
1、加锁顺序(线程按照一定的顺序加锁);
若让上述两个线程都先获取资源o1的锁,死锁情况就不会发生
2、加锁时限(线程尝试获取锁的时候加上一定的时限,超过时限则放弃对该锁的请求,并释放自己占有的锁);
加锁时效的原理就是:给每一个访问线程增加访问时效,若一个线程没有在给定的时限内成功获得所有需要的锁,则会进行回退并释放所有已经获得的锁(此时就打破了造成死锁的四个原因中的第三个原因),然后等待一段随机的时间再重试。