服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - 解决Spring session(redis存储方式)监听导致创建大量redisMessageListenerContailner-X线程问题

解决Spring session(redis存储方式)监听导致创建大量redisMessageListenerContailner-X线程问题

2021-05-29 12:26aoeiuv Java教程

这篇文章主要介绍了解决Spring session(redis存储方式)监听导致创建大量redisMessageListenerContailner-X线程问题,需要的朋友可以参考下

待解决的问题

spring session(redis存储方式)监听导致创建大量redismessagelistenercontailner-x线程

解决办法

为spring session添加springsessionredistaskexecutor线程池。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
 * 用于spring session,防止每次创建一个线程
 * @return
 */
@bean
public threadpooltaskexecutor springsessionredistaskexecutor(){
  threadpooltaskexecutor springsessionredistaskexecutor = new threadpooltaskexecutor();
  springsessionredistaskexecutor.setcorepoolsize(8);
  springsessionredistaskexecutor.setmaxpoolsize(16);
  springsessionredistaskexecutor.setkeepaliveseconds(10);
  springsessionredistaskexecutor.setqueuecapacity(1000);
  springsessionredistaskexecutor.setthreadnameprefix("spring session redis executor thread: ");
  return springsessionredistaskexecutor;
}

原因

在spring session(redis)的配置类源码中(redishttpsessionconfiguration):

?
1
2
3
4
5
6
7
@autowired(
  required = false  //该处理监听的线程池不是必须的,如果不自定义默认将使用simpleasynctaskexecutor线程池
)
@qualifier("springsessionredistaskexecutor")
public void setredistaskexecutor(executor redistaskexecutor) {
  this.redistaskexecutor = redistaskexecutor;
}

springsessionredistaskexecutor不是必须的,如果不自定义则spring默认将使用simpleasynctaskexecutor线程池。

题外话

simpleasynctaskexecutor:每次都将创建新的线程(说是“线程池”,其实并非真正的池化,但它可以设置最大并发线程数量。)

@enableasync开启异步方法,背后默认使用的就是这个线程池。使用异步方法时如果业务场景存在频繁的调用(该异步方法),请自定义线程池,以防止频繁创建线程导致的性能消耗。如果该异步方法存在阻塞的情况,又调用量大,注意有可能导致oom(线程还未结束,又增加了更多的线程,最后导致内存溢出)。@async注解可以选择使用自定义线程池。

它创建了simpleasynctaskexecutor

说回redishttpsessionconfiguration,我们接着看:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@bean
public redismessagelistenercontainer redismessagelistenercontainer() {
  redismessagelistenercontainer container = new redismessagelistenercontainer();
  container.setconnectionfactory(this.redisconnectionfactory);
  if (this.redistaskexecutor != null) {
    container.settaskexecutor(this.redistaskexecutor);
  }
  if (this.redissubscriptionexecutor != null) {
    container.setsubscriptionexecutor(this.redissubscriptionexecutor);
  }
  container.addmessagelistener(this.sessionrepository(), arrays.aslist(new patterntopic("__keyevent@*:del"), new patterntopic("__keyevent@*:expired")));
  container.addmessagelistener(this.sessionrepository(), collections.singletonlist(new patterntopic(this.sessionrepository().getsessioncreatedchannelprefix() + "*")));
  return container;
}
redismessagelistenercontainer正是处理监听的类,redismessagelistenercontainer设置了不为空的redistaskexecutor,因为spring session默认没有配置该executor,那redismessagelistenercontainer在处理监听时怎么使用线程呢?我们接着看redismessagelistenercontainer的源码:
public void afterpropertiesset() {
  if (this.taskexecutor == null) {
    this.manageexecutor = true;
    this.taskexecutor = this.createdefaulttaskexecutor();
  }
  if (this.subscriptionexecutor == null) {
    this.subscriptionexecutor = this.taskexecutor;
  }
  this.initialized = true;
}
protected taskexecutor createdefaulttaskexecutor() {
  string threadnameprefix = this.beanname != null ? this.beanname + "-" : default_thread_name_prefix;
  return new simpleasynctaskexecutor(threadnameprefix);
}

afterpropertiesset()这个方法熟悉吧,这个方法将在所有的属性被初始化后调用(initializingbean接口细节这里不再赘述)。

 所以如果用户没有定义springsessionredistaskexecutor,spring session将调用createdefaulttaskexecutor()方法创建simpleasynctaskexecutor线程池。而这个“线程池”处理任务时每次都创建新的线程。所以你会发现很多个redismessagelistenercontailner-x线程。

总结

以上所述是小编给大家介绍的解决spring session(redis存储方式)监听导致创建大量redismessagelistenercontailner-x线程问题,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对服务器之家网站的支持!

原文链接:https://www.cnblogs.com/aoeiuv/p/9565617.html

延伸 · 阅读

精彩推荐