导航菜单

丹阳-Java中的线程死锁是什么?怎样处理这个问题?

线程死锁便是多个线程一起被堵塞,它们中的一个或许悉数都在等候某个资源被开释。由于线程被无限期地堵塞,因而程序不可能正常停止。

如下图所示,线程 A 持有资源 2,线程 B 持油菜有资源 1,他们一起都想恳求对方的资源,所以这两个线程就会相互等候而进入死锁状况。

这个问题许多Java程序员在面试中会遇到,那么怎么处理线程死锁的问题呢?下面跟小编一起来看看:

死锁示意图

下面经过一个比如来阐明线程死锁,代码模拟了上图的死锁的状况 (代码来源于《并发编程之美》):

public class DeadLockDemo {
private static Object resource1 = new Object();//资源 1
private static Object resource2 = new Object();//资源 2
public static void main(Strin丹阳-Java中的线程死锁是什么?怎样处理这个问题?g[] args) {
new Thread(() -> {
synchronized (resource1) {
System.out.println(Thread.currentThread() + "get resource1");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread() + "waiting get resource2");
synchronized (resource2) {
System.out.println(Thread.currentThread() + "get resource2");
}
}
}, "线程 1").start();
new Thread(() -> {
synchronized (resource2) {
System.out.println(Thread.currentThread() + "get resource2");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread() + "waiting get resource1");
synchronized (resource1) {
System.out.println(Thread.currentThread() + "get resource1");
}
}
}, "线程 2").start();
}
}

Output

1 Thread[线程 1,5,main]get resource1
2 Thread[线程 2,5,main]get resource2
3 Thread[线程 1,5,main]waiting get resource2
4 Thread[线程 2,5,main]waiting get resource1

线程 A 经过 synchronized (resource1) 取得 resource1 的监视器锁,然后经过Thread.sleep(1000);让线程 A 休眠 1s 为的是让线程 B 得到履行然后获取到 resource2 的监视器锁。线程 A 和线程 B 休眠结束了都开端妄图恳求获取对方的资源,然后这两个线程就会堕入相互等候的状况,这也就发作了死锁。上面的比如契合发作死锁的四个必要条件。

学过操作系统的朋友都知道发作死锁有必要具有以下四个条件:

1.互斥条件:该资源恣意一个时间只由一个线程占用。

2.恳求与坚持条件:一个进程因恳求资源而堵塞时,对已取得的资源坚持不放。

3.不掠夺条件:线程已取得的资源在末运用完之前不能被其他线程强行掠夺,只要自己运用结束后才开释资源。

4.循环等候条件:若干进程之间构成一种头尾相接的循环等候资源联系。

怎么防止线程死锁?

损坏互斥条件

这个条件咱们没有办法损坏,由于咱们用锁原本便是想让他们互斥的(临界资源需求互斥拜访)。

损坏恳求与坚持条件

一次性恳求一切的资源。

损坏不掠夺条件

占用部分资源的线程进一步恳求其他资源时,假如恳求不到,能够自动开释它占有的资源。

损坏循环等候条件

靠按序恳求资源来防备。按某一次序恳求资源,开释资源则反序开释。损坏循环等候条件。 咱们对线程 2 的代码修改成下面这样就不会发作死锁了。

new Thread(() -> {
synchronized (res丹阳-Java中的线程死锁是什么?怎样处理这个问题?ource1) {
System.out.println(Thread.currentThread() + "get resource1");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread() + "waiting get resource2");
synchronized (resource2) {
System.out.println(Thread.currentTh丹阳-Java中的线程死锁是什么?怎样处理这个问题?read() + "get resource2");
}
}
}, "线程 2").start();

Output

Thread[线程 1,5,main]get resource1
Thread[线程 1,5,main]waiting get resource2
Thread[线程 1,5,main]get resource2
Thread[线程 2,5,main]get r丹阳-Java中的线程死锁是什么?怎样处理这个问题?esource1
Thread[线程 2,5,main]waiting get resource2
Thread[线程 2,5,main]get resource2
Process finished with exit code 0

咱们剖析一下上面的代码为什么防止了死锁的发作?

线程 1 首要取得到 resource1 的监视器锁,这时候线程 2 就获取不到了。然后线程 1 再去获取 resource2 的监视器锁,能够获取到。然后线程 1 开释了对 resource1、resource2 的监视器锁的占用,线程 2 获取到就能够履行了。这样就损坏了损坏循环等候条件,因而防止了死锁。

经过以上的解说不知道我们关于Java中的线丹阳-Java中的线程死锁是什么?怎样处理这个问题?程死锁问题有没有了解清楚,想要获取更多Java行业动态和学习材料,能够重视“武汉千锋”微信大众号!

二维码