线城死锁就是指两个或两个以上的线程在抢占资源时,造成相互等待的现象,称为死锁。在没有外力的情况下是会一直等待无法执行下去的。
1. 死锁产生必须具备以下条件
- **互斥条件:**指线程获取到的资源进行排它性使用,即当获取该资源锁的时候其他线程是获取不到该锁资源的。
- **请求并持有:**当线程持有资源时,又要请求其他锁资源,但是其他所资源被其他线程所占有。但是等待的时候并不会释放自己所占有的资源。
- **不可剥夺条件:**自己获取的所资源当没有使用完的时候不释放锁资源。
- **环路等待条件:**环路等待就是就是线程需求形成一个环形链。比如有【T0…Tn】个线程,T0需要T1占有的锁资源,T1需要T2的锁资源…Tn需要T0的锁资源。
例:
public class User {
private static Object objectA = new Object();
private static Object objectB = new Object();
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
synchronized (objectA){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("111111111111");
synchronized (objectB){
System.out.println("222222222222");
}
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (objectB){
Thread.sleep(1000);
System.out.println("3333333333333");
synchronized (objectA){
System.out.println("44444444444444");
}
}
}
}).start();
}
}
分析:首先objectA、objectB都是互斥资源。当第一个线程获取到objectA资源时,还需要请求objectB资源,当第一个线程获取到objectB资源时,还需要请求objectA资源。这样就造成了请求并持有条件。第一个和第二个获取的资源当他们没有执行结束时都不可被剥夺,这样就形成资源不可剥夺条件。第一个线程需要objectB资源,造成在等待 持有objectA资源,第二个线程需要objectA资源,造成在等待objectA的时候 持有objectB资源,这就形成了环路等待条件,所以就造成了死锁。
2. 如何避免死锁
避免死锁只需要把四种中的一个给破坏掉就可以了。但是我们只能破回掉,环路等待条件和请求并持有条件。
造成死锁的条件其实和线程请求资源的顺序有很大的关系,使用资源的有序性原则就能很大可能的避免死锁。
例:
public class User {
private static Object objectA = new Object();
private static Object objectB = new Object();
public static void main(String[] args) {
new Thread(new Runnable() {
@Override
public void run() {
synchronized (objectA){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("111111111111");
synchronized (objectB){
System.out.println("222222222222");
}
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
synchronized (objectA){
System.out.println("3333333333333");
synchronized (objectB){
System.out.println("44444444444444");
}
}
}
}).start();
}
}
如上代码就是把这两个线程申请的资源顺序给调成一样的了,这样就可以避免死锁,当第一个线程请求完毕,另一个线程才能占有资源,这样就不会造成线程的死锁了。