当前位置: 首页 > 图灵资讯 > 技术篇> 深入理解Java内存模型与死锁问题

深入理解Java内存模型与死锁问题

来源:图灵教育
时间:2024-03-27 15:57:57

Java 内存模型与死锁:深入理解并发编程中的死锁问题

Java 内存模型(JMM)它定义了一套规范 Java 变量在多个程序中是如何变量的?共享线程。JMM 规定了线程如何从主内存中读取和写入变量,以及如何将变量值存储在主内存中。

锁是并发编程中的一个常见问题发生在两个或多个线程等待释放锁。当一个线程持有锁时,如果另一个线程试图获得锁,则第二个线程将被阻塞。如果两个线程都持有彼此需要的锁,那么就会发生死锁。

为解决死锁问题,可采用以下方法:

  • 避免锁:尽量避免在代码中创建锁的条件。例如,不要在同一对象上使用多个锁,也不要让一个线程等待另一个线程释放锁。
  • 使用锁加班:在获得锁时指定一个加班时间。如果锁不能在加班时间内获得,线程将抛出异常并继续执行。
  • 使用中断:当一个线程等待另一个线程释放锁时,中断信号可以发送到等待线程。如果线程收到中断信号,它将被抛出 InterruptedException 异常并继续执行。

以下是演示死锁的示例代码:

public class DeadlockExample {

private static Object lock1 = new Object();
private static Object lock2 = new Object();

public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
synchronized (lock1) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2) {
System.out.println("Thread 1 acquired both locks");
}
}
});

Thread thread2 = new Thread(() -> {
synchronized (lock2) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock1) {
System.out.println("Thread 2 acquired both locks");
}
}
});

thread1.start();
thread2.start();
}
}

在这个示例代码中,两个线程试图同时获得两个锁。线程 1 先获取了锁 然后试着获得锁 2。线程 2 先获取了锁 然后试着得到锁 1.死锁发生了,因为两个线程都持有彼此需要的锁。

为了解决这个死锁问题,代码可以修改如下:

public class DeadlockExample {

private static Object lock1 = new Object();
private static Object lock2 = new Object();

public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
synchronized (lock1) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock2) {
System.out.println("Thread 1 acquired both locks");
}
}
});

Thread thread2 = new Thread(() -> {
synchronized (lock2) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lock1) {
System.out.println("Thread 2 acquired both locks");
}
}
});

thread1.start();
thread2.start();

thread1.join();
thread2.join();
}
}

我们在修改后的代码中使用了它 join() 方法等待线程完成。这样,线程就可以得到保证 1 在获取了锁 1 后再获取锁 2,而线程 2 在获取了锁 2 后再获取锁 1.这样,死锁就不会发生。