gpt4 book ai didi

Java 保证死锁

转载 作者:行者123 更新时间:2023-12-01 19:38:06 24 4
gpt4 key购买 nike

我有两门课:

Deadlock1.java

class Client {
final Object resource1 = "resource1";
final Object resource2 = "resource2";
void doS1() {
synchronized(resource1) {}
}
void doS2() {
synchronized(resource2) {}
}
}

public class Deadlock1 {
public static void main(String[] args) {
Client client = new Client();
new Thread(
() ->
{
client.doS1();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
}
client.doS2();
}).start();

new Thread(
() ->
{
client.doS2();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
}
client.doS1();
}).start();
}
}

Deadlock2.java

class Client {
final Object resource1 = "resource1";
final Object resource2 = "resource2";
}

public class Deadlock2{
public static void main(String[] args) {
Client client = new Client();

new Thread(
() ->
{
synchronized (client.resource1) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
}

synchronized (client.resource2) {}
}
}).start();

new Thread(
() ->
{
synchronized (client.resource2) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
}
synchronized (client.resource1) {}
}
}).start();
}
}

在 Deadlock1 中没有发生死锁,但在 Deadlock2 中却发生了。我不明白为什么?而且我不太明白同步块(synchronized block)概念的含义。为什么这个 block 是线程代码的一部分,而不是不同线程执行的一些公共(public)代码?

最佳答案

同步块(synchronized block)可防止在同一监视器对象上同时执行代码。在本例中,doS1() 的监视对象是resource1,而在 doS2() 中,监视对象是resource2。当线程进入同步块(synchronized block)时,它会尝试获取监视器对象上的锁。如果它获得了锁,那么只有当它退出 block (或者释放锁)时,它才会继续并释放锁。如果它无法获得锁(因为另一个线程已经拥有锁,那么该线程将阻塞,直到锁被释放并且它可以获取它)。

上面的两个示例,Deadlock1Deadlock2,没有执行等效的代码。在Deadllock1中,两个监视器对象锁不能同时被同一个线程获取。

Deadlock2中,每个线程都尝试同时获取两个监视器对象上的锁。

  1. 线程 1 获取资源 1 的锁并 hibernate 50 毫秒
  2. 同时线程 2 获取资源 2 的锁并 hibernate 50 毫秒
  3. 当线程 1 继续运行时,它仍然拥有资源 1 上的锁,并尝试获取资源 2 上的锁。资源 2 锁仍由线程 2 持有,因此它会阻塞等待资源 2 被释放。
  4. 与此同时,线程 2 尝试获取资源 1 上的锁,但这仍然由线程 1 持有,因此它会阻塞等待线程 1 释放资源 1 的监视器。
  5. 现在两个线程都被阻塞,等待监视器对象被释放,并且由于它们都被阻塞,所以它们无法释放它们锁定的监视器对象......因此出现死锁。

如果我们重写Deadlock1来模仿Deadlock2的功能,这样它就会产生死锁,它看起来像这样:

public class Deadlock1 {
static class Client {
final Object resource1 = "resource1";
final Object resource2 = "resource2";

void doS1() {
synchronized (resource1) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
}
doS2();
}
}

void doS2() {
synchronized (resource2) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
}
doS1();
}
}
}

public static void main(String[] args) {
Client client = new Client();
new Thread(client::doS1).start();
new Thread(client::doS2).start();
}
}

或者,如果我们重写 Deadlock2 来模仿 Deadlock1 的功能,这样它就不会产生死锁,它看起来像这样:

public class Deadlock2 {
static class Client {
final Object resource1 = "resource1";
final Object resource2 = "resource2";
}

public static void main(String[] args) {
Client client = new Client();

new Thread(
() ->
{
synchronized (client.resource1) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
}

}
synchronized (client.resource2) {}
}).start();

new Thread(
() ->
{
synchronized (client.resource2) {
try {
System.out.println("3");
Thread.sleep(50);
} catch (InterruptedException e) {
}
}
synchronized (client.resource1) {}
}).start();
}
}

关于Java 保证死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56652683/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com