什么是死锁?(把死锁给大家讲明白,知道是什么,为什么用,怎么用)-CSDN博客
什么是死锁,产生死锁的必要条件,以及避免死锁的方法-CSDN博客
讲得特别特别的好 常看常新
package com.example;
public class Deadlock {
public static String str1 = "str1";
public static String str2 = "str2";
public static void main(String[] args){
Thread a = new Thread(() -> {
try{
while(true){
synchronized(Deadlock.str1){
System.out.println(Thread.currentThread().getName()+"锁住 str1");
Thread.sleep(1000);
synchronized(Deadlock.str2){
System.out.println(Thread.currentThread().getName()+"锁住 str2");
}
}
}
}catch(Exception e){
e.printStackTrace();
}
});
Thread b = new Thread(() -> {
try{
while(true){
synchronized(Deadlock.str2){
System.out.println(Thread.currentThread().getName()+"锁住 str2");
Thread.sleep(1000);
synchronized(Deadlock.str1){
System.out.println(Thread.currentThread().getName()+"锁住 str1");
}
}
}
}catch(Exception e){
e.printStackTrace();
}
});
a.start();
b.start();
}
}
- 初始化资源: str1 和 str2 是两个静态字符串资源,代表要被两个线程访问和锁定的资源。
- 线程a的操作:
- 线程a开始执行,并首先尝试锁定str1(synchronized(Deadlock.str1))。
- 成功锁定str1后,线程a输出“锁住 str1”,然后进入sleep状态(模拟耗时操作)。这个sleep期间,它保持着对str1的锁定。
- sleep结束后,线程a尝试锁定str2(synchronized(Deadlock.str2))。但是,如果线程b已经锁定了str2,线程a将在这里等待,直到str2变得可用(即被释放)。
- 线程b的操作:
- 线程b几乎同时开始执行,并首先尝试锁定str2(synchronized(Deadlock.str2))。
- 成功锁定str2后,线程b输出“锁住 str2”,然后同样进入sleep状态(模拟耗时操作)。这期间,它保持着对str2的锁定。
- sleep结束后,线程b尝试锁定str1(synchronized(Deadlock.str1))。但是,如果线程a已经锁定了str1,线程b将在这里等待,直到str1变得可用。
- 死锁产生:
- 如果线程a和线程b分别锁定了str1和str2,且都在等待对方释放锁,就会出现死锁。
- 线程a等待str2被释放,而线程b等待str1被释放。但是,它们都不会释放自己已经持有的锁,因为它们都在等待获取第二个锁才能继续执行,导致了无法解决的循环等待状态。
在这个例子中,死锁的根本原因是两个线程以不同的顺序请求相同的资源。线程a先请求str1然后是str2,而线程b先请求str2然后是str1。这种锁请求顺序的不一致性是产生死锁的关键因素。