服务器之家

服务器之家 > 正文

spring容器初始化遇到的死锁问题解决

时间:2021-05-13 11:24     来源/作者:aitangyong

前言

最近启动spring项目的时候遇到一个死锁问题,使用jstack获取线程堆栈的时候,可以看到2个线程出现了死锁:

spring容器初始化遇到的死锁问题解决

解决过程:

defaultsingletonbeanregistry.getsingleton()源码如下,可以看到这个方法需要对singletonobjects加锁

spring容器初始化遇到的死锁问题解决

第二处xxx.subject.core.cache.datalocalcacheinit.afterpropertiesset源码如下:

spring容器初始化遇到的死锁问题解决

可以看到:这个bean在初始化的时候,会开启线程,调用另外一个bean的initdata()方法从数据库加载数据。等数据加载完毕,datalocalcacheinit这个bean的初始化才算完成。

通过上面的堆栈可以看出:spring容器在初始化bean的时候,会对singletonobjects对象加锁;我们自己在afterpropertiesset()方法中开启了一个线程,最终也会触发spring加载另外的bean。第一个线程(初始化spring的main线程)还没有释放锁,第二个线程(自己开启的线程),也需要获取singletonobjects对象锁,这样就出现了死锁。表现出来的现象就是:spring容器卡在那里,不能完成所有bean的初始化。

来看一段例子,这个例子和我们项目中实际代码很相似。firstbean调用confighelper中的方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class firstbean implements initializingbean {
 
 @override
 public void afterpropertiesset() throws exception {
  system.out.println("first bean is initializing....");
 
  blockingqueue queue = new arrayblockingqueue(10);
  thread thread = new thread() {
 
   @override
   public void run() {
    confighelper.dosomething();
    queue.add(1);
   }
  };
 
  thread.start();
 
  queue.take();
  system.out.println("first get data....");
 
 }
}

confighelper代码如下:通过beanfactory获取到另外一个bean

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class confighelper implements beanfactoryaware {
 private static beanfactory factory;
 
 @override
 public void setbeanfactory(beanfactory beanfactory) throws beansexception {
  this.factory = beanfactory;
 }
 
 public static void dosomething()
 {
  secondbean bean = (secondbean)factory.getbean("second");
  bean.say();
 }
}

secondbean代码很简单如下:

?
1
2
3
4
5
public class secondbean {
 public void say() {
  system.out.println("secondbean....");
 }
}

spring配置文件和启动代码如下,运行可以发现出现死锁:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?xml version="1.0" encoding="utf-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
  xsi:schemalocation="http://www.springframework.org/schema/beans
  http://www.springframework.org/schema/beans/spring-beans.xsd">
 
 
 <bean id="config" class="net.aty.spring.deadlock.confighelper"></bean>
 <bean id="first" class="net.aty.spring.deadlock.firstbean"></bean>
 <bean id="second" class="net.aty.spring.deadlock.secondbean"></bean>
 
</beans>
public class main {
 public static void main(string[] args) {
  applicationcontext context = new filesystemxmlapplicationcontext(
    "src/main/java/net/aty/spring/deadlock/deadlock.xml");// 加载 spring 配置文件
 
 }
}

spring容器初始化遇到的死锁问题解决

spring初始化的时候,如果我们在spring提供的一些扩展点处(beanfactoryaware/initializingbean等),开启线程去获取bean,很容器出现死锁。因为spring初始化单例bean(大多数bean都是单例的)会加锁。如果初始化1个bean的时候,还没有释放锁,另一个线程再次触发spring加载bean,就会出现死锁。

解决上面的问题很简单:firstbean逻辑上是依赖于confighelper和secondbean的,但是我们却并没有显示地告诉spring这种逻辑关系。spring初始化firstbean的时候,进入afterpropertiesset() ,这个方法开启了线程会触发另外2个bean的加载。我们只要显示地告诉spring这种依赖关系,让spring先加载confighelper和secondbean就可以了。

?
1
2
3
<bean id="config" class="net.aty.spring.deadlock.confighelper" depends-on="second"></bean>
<bean id="first" class="net.aty.spring.deadlock.firstbean" depends-on="config"></bean>
<bean id="second" class="net.aty.spring.deadlock.secondbean"></bean>

spring容器初始化遇到的死锁问题解决

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对服务器之家的支持。

原文链接:https://blog.csdn.net/aitangyong/article/details/53036913

相关文章

热门资讯

2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全 2019-12-26
yue是什么意思 网络流行语yue了是什么梗
yue是什么意思 网络流行语yue了是什么梗 2020-10-11
背刺什么意思 网络词语背刺是什么梗
背刺什么意思 网络词语背刺是什么梗 2020-05-22
苹果12mini价格表官网报价 iPhone12mini全版本价格汇总
苹果12mini价格表官网报价 iPhone12mini全版本价格汇总 2020-11-13
2021德云社封箱演出完整版 2021年德云社封箱演出在线看
2021德云社封箱演出完整版 2021年德云社封箱演出在线看 2021-03-15
返回顶部