温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

怎么解决Spring session监听导致创建大量redisMessageListenerContailner-X线程问题

发布时间:2021-06-07 11:38:31 来源:亿速云 阅读:1194 作者:小新 栏目:编程语言

这篇文章主要为大家展示了“怎么解决Spring session监听导致创建大量redisMessageListenerContailner-X线程问题”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“怎么解决Spring session监听导致创建大量redisMessageListenerContailner-X线程问题”这篇文章吧。

待解决的问题

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

解决办法

为spring session添加springSessionRedisTaskExecutor线程池。

/**
 * 用于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):

@Autowired(
  required = false  //该处理监听的线程池不是必须的,如果不自定义默认将使用SimpleAsyncTaskExecutor线程池
)
@Qualifier("springSessionRedisTaskExecutor")
public void setRedisTaskExecutor(Executor redisTaskExecutor) {
  this.redisTaskExecutor = redisTaskExecutor;
}

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

题外话

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

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

它创建了SimpleAsyncTaskExecutor

说回RedisHttpSessionConfiguration,我们接着看:

@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监听导致创建大量redisMessageListenerContailner-X线程问题”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注亿速云行业资讯频道!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI