前言
最近发现在启动一个项目花的时间很长,结果是一直卡死,启不起来。经过排查发现,其中是springboot自动装配自定义的配置类用来创建对象时,在加载类阶段的初始化时发生了死锁,笔者用简单代码模拟一下发生死锁的情况:
public class TestInit1 {
static {
System.out.println("初始化类1……");
try {
Class.forName("org.example.leetcode.TestInit2");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
public class TestInit2 {
static {
System.out.println("初始化类2……");
try {
Class.forName("org.example.leetcode.TestInit1");
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
}
/**
* @Data 12/08,24
* @Describe 多线程同时创建两个对象
*/
public class TestDemo {
public static void main(String[] args) {
System.out.println("开始执行……");
new Thread(()->{
new TestInit2();
}).start();
new Thread(()->{
new TestInit1();
}).start();
}
}
执行结果
发生了死锁
分析发生死锁原因
翻看hospot的JVM源码,它对于一个类的初始化流程如下:
简单来说,在一个类的加载阶段中的初始化时,是会加锁的。例如线程1创建类A时,去初始化类A,先加锁1,初始化的逻辑要去初始化类B,就要去争抢锁2,与此同时,线程2创建类B时,去初始化类B,先加锁2,它也要去初始化类A,要等待锁1的释放,于是形成了死锁。
解决方案:
①互相初始化时,就不要用多个线程同步去初始化;
②即使为了加快创建效率,要用多线程同时初始化,也要提前检查代码看是否会出现死锁问题才行;