线程死锁
面试题,请写一个线程死锁的代码。
首先需要明白什么是死锁?
死锁,是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种相互等待的现象,若无外力作用,它们将无法推进下去,此时称系统处于死锁状态或系统产生了死锁。
常见产生死锁的原因有哪些?
系统资源不足;进程运行顺序不合适;资源分配不相等;进程运行速度不同也可能产生死锁(类似于执行顺序)。
产生死锁的四个必要条件?这四个条件其实在对死锁的定义进行解释。
1)互斥条件,一个资源每次只能被一个进程使用;(两个或两个以上进程执行)
2)请求与保持条件,一个进程请求资源阻塞时,对获得的资源保持占用,不释放(因争夺资源而造成的一种相互等待的现象)
3)不解除资源占用;这里其实指无外力作用;在资源未使用完之前,无外力强制解除资源占用(若无外力作用,它们将无法推进下去)
4)循环等待条件,若干进程直接形成一种头尾相接的循环等待资源关系。(相互等待的现象)
这四个必要条件,有一个条件不成立,就不能形成死锁。
上面说清楚了定义,条件,那么代码只需要根据条件来编写。如下,是我写的一个线程死锁的Demo
package mytest;
public class TestThreadDeadLock { //定义一个死锁类
//死锁满足四个条件;1,互斥条件;2,请求和保持资源占用;3,无外力不解除占用;4,相互引用循环等待
//1,互斥,来两个类ThreadA,ThreadB
//2,资源占用,来写一个资源source数组
static String[] source = new String[] {"资源1","资源2"};
static class ThreadA implements Runnable{
@Override
public void run() {
synchronized(source[0]) {//请求资源并保持资源占用资源1
System.out.println("ThreadA在使用资源:"+source[0]);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized(source[1]) {//去请求使用资源2;而此时另一个线程ThreadB在使用资源2;
System.out.println("ThreadA将要使用资源:"+source[1]);
}
}
}
}
static class ThreadB implements Runnable{
@Override
public void run() {
synchronized(source[1]) {//请求资源并保持资源占用资源2
System.out.println("ThreadB在使用资源:"+source[1]);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized(source[0]) {//此时另一个线程ThreadA,在占用资源1;
System.out.println("ThreadA将要使用资源:"+source[0]);
}
}
}
}
public static void main(String args[]) {
ThreadA a = new ThreadA();
ThreadB b = new ThreadB();
new Thread(a).start();
new Thread(b).start();
//线程同时启动,资源被相互占用,又相互循环,无外力能强制解除资源占用。此时,造成死锁。
//不要怀疑是程序卡住了。写个守护线程验证一下
DaemondThread daemond = new DaemondThread();
daemond.start();
}
static class DaemondThread extends Thread{//线程的两种方式,继承Thread,或实现Runnable
public void run() {
while(true) {
System.out.println("守护线程执行中。。。");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
下面是运行结果
从结果可以看到,ThreadA和ThreadB都占用了一个资源,在等待彼此使用完另外一个资源释放;这样就在资源相互请求和资源占用过程中,又无外力强制释放资源,而使程序形成了死锁。
多说一句;如何解除死锁呢?
只需要破坏四个条件中的一个,便可以解除死锁。如上面代码,如何解除呢?
只需要将两个线程占用资源的顺序改为一样的,便可解除死锁。如下图:
死锁讨论至此结束