首页 > 图灵资讯 > 技术篇>正文
深入理解Java内存模型与死锁问题
2024-03-27 15:57:57
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.这样,死锁就不会发生。