多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。
如下图所示,线程 A 持有资源 2,线程 B 持有资源 1,他们同时都想申请对方的资源,所以这两个线程就会互相等待而进入死锁状态。
下面通过一个例子来说明线程死锁,代码模拟了上图的死锁的情况 (代码来源于《并发编程之美》):
public class DeadLockDemo {
private static Object resource1 = new Object();//资源 1
private static Object resource2 = new Object();//资源 2
public static void main(String[] 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
Thread[线程 1,5,main]get resource1
Thread[线程 2,5,main]get resource2
Thread[线程 1,5,main]waiting get resource2
Thread[线程 2,5,main]waiting get resource1
线程 A 通过 synchronized (resource1) 获得 resource1 的监视器锁,然后通过Thread.sleep(1000);
让线程 A 休眠 1s 为的是让线程 B 得到执行然后获取到 resource2 的监视器锁。线程 A 和线程 B 休眠结束了都开始企图请求获取对方的资源,然后这两个线程就会陷入互相等待的状态,这也就产生了死锁。上面的例子符合产生死锁的四个必要条件。
学过操作系统的朋友都知道产生死锁必须具备以下四个条件:
我们只要破坏产生死锁的四个条件中的其中一个就可以了。
破坏互斥条件
这个条件我们没有办法破坏,因为我们用锁本来就是想让他们互斥的(临界资源需要互斥访问)。
破坏请求与保持条件
一次性申请所有的资源。
破坏不剥夺条件
占用部分资源的线程进一步申请其他资源时,如果申请不到,可以主动释放它占有的资源。
破坏循环等待条件
靠按序申请资源来预防。按某一顺序申请资源,释放资源则反序释放。破坏循环等待条件。
我们对线程 2 的代码修改成下面这样就不会产生死锁了。
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");
}
}
}, "线程 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 resource1
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 获取到就可以执行了。这样就破坏了破坏循环等待条件,因此避免了死锁。
主要内容:示例资源分配图是系统状态的图形表示。 顾名思义,资源分配图是关于持有一些资源或等待某些资源的所有进程的完整信息。 它还包含有关所有资源的所有实例的信息,无论这些资源是否可用或正在被进程使用。 在资源分配图中,进程由圆形表示,而资源由矩形表示。 我们来详细看看顶点和边的类型。 顶点主要有两种类型,资源和过程。 它们中的每一个将以不同的形状表示。 Circle代表进程,而矩形代表资源。 一个资源可以有多个
在避免死锁的情况下,如果系统的结果状态不会导致系统中的死锁,那么将会授予对任何资源的请求。系统的状态将持续检查安全和不安全的状态。 为了避免死锁,进程必须告诉OS,进程可以请求完成其执行的最大资源数量。 最简单和最有用的方法指出,流程应声明它可能需要的每种类型的最大资源数量。 死锁避免算法检查资源分配,以便永远不会有循环等待条件。 安全和不安全的状态 系统的资源分配状态可以由可用资源和已分配资源的
问题内容: 某些数据库功能(例如和)很容易受到死锁的影响,因为数据库未指定将使用哪种锁定顺序。我发现有两次 讨论暗示此行为不是SQL标准指定的,更不用说具体的实现了。因此,我在假设我们无法控制锁定顺序的情况下进行操作(至少,这样做并不明显)。 如果我们不能依赖锁定顺序,应该如何避免数据库死锁? 如果我们不应该避免僵局(您将不得不非常努力地说服我),那么我们应该怎么做? 这个问题与数据库无关,所以请
我已经在Jenkins安装上配置了两个多分支项目(来自GitHub)。目前遗嘱执行人的数量是四个。 有时,当有很多分支要构建时,它最终会出现所有执行器都在等待免费执行器而什么都没有发生的情况。 你通常如何避免这种情况?当然,人们不能在一台机器上配置一百万个执行器来确保这种情况永远不会发生。 我现在有四个执行者试图构建,他们都在等待对方: 另一个问题是,这是如何/为什么可能的?他们没有实施任何机制来
主要内容:1 什么是Java线程死锁,2 Java线程死锁的例子1 什么是Java线程死锁 Java中的死锁是多线程的一部分。当线程正在等待由另一个线程获取的对象锁而第二个线程正在等待由第一个线程获取的对象锁时,可能会发生死锁。由于两个线程都在互相等待释放锁,因此这种情况称为死锁。 2 Java线程死锁的例子 输出结果为:
我使用test_and_set方法让其他线程先等待,线程t1可以中断while循环,但即使在线程t1将值设置为0之后。线程t2继续运行while循环,它不会中断while循环。应该做哪些改变?。