解决Spring session(redis存储方式)监听导致创建大量redisMessageListenerContailner-X线程问题
待解决的问题
Springsession(redis存储方式)监听导致创建大量redisMessageListenerContailner-X线程
解决办法
为springsession添加springSessionRedisTaskExecutor线程池。
/** *用于springsession,防止每次创建一个线程 *@return */ @Bean publicThreadPoolTaskExecutorspringSessionRedisTaskExecutor(){ ThreadPoolTaskExecutorspringSessionRedisTaskExecutor=newThreadPoolTaskExecutor(); springSessionRedisTaskExecutor.setCorePoolSize(8); springSessionRedisTaskExecutor.setMaxPoolSize(16); springSessionRedisTaskExecutor.setKeepAliveSeconds(10); springSessionRedisTaskExecutor.setQueueCapacity(1000); springSessionRedisTaskExecutor.setThreadNamePrefix("Springsessionredisexecutorthread:"); returnspringSessionRedisTaskExecutor; }
原因
在SpringSession(redis)的配置类源码中(RedisHttpSessionConfiguration):
@Autowired( required=false//该处理监听的线程池不是必须的,如果不自定义默认将使用SimpleAsyncTaskExecutor线程池 ) @Qualifier("springSessionRedisTaskExecutor") publicvoidsetRedisTaskExecutor(ExecutorredisTaskExecutor){ this.redisTaskExecutor=redisTaskExecutor; }
springSessionRedisTaskExecutor不是必须的,如果不自定义则spring默认将使用SimpleAsyncTaskExecutor线程池。
题外话
SimpleAsyncTaskExecutor:每次都将创建新的线程(说是“线程池”,其实并非真正的池化,但它可以设置最大并发线程数量。)
@EnableAsync开启异步方法,背后默认使用的就是这个线程池。使用异步方法时如果业务场景存在频繁的调用(该异步方法),请自定义线程池,以防止频繁创建线程导致的性能消耗。如果该异步方法存在阻塞的情况,又调用量大,注意有可能导致OOM(线程还未结束,又增加了更多的线程,最后导致内存溢出)。@Async注解可以选择使用自定义线程池。
它创建了SimpleAsyncTaskExecutor
说回RedisHttpSessionConfiguration,我们接着看:
@Bean publicRedisMessageListenerContainerredisMessageListenerContainer(){ RedisMessageListenerContainercontainer=newRedisMessageListenerContainer(); 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(newPatternTopic("__keyevent@*:del"),newPatternTopic("__keyevent@*:expired"))); container.addMessageListener(this.sessionRepository(),Collections.singletonList(newPatternTopic(this.sessionRepository().getSessionCreatedChannelPrefix()+"*"))); returncontainer; } RedisMessageListenerContainer正是处理监听的类,RedisMessageListenerContainer设置了不为空的redisTaskExecutor,因为springsession默认没有配置该Executor,那RedisMessageListenerContainer在处理监听时怎么使用线程呢?我们接着看RedisMessageListenerContainer的源码: publicvoidafterPropertiesSet(){ if(this.taskExecutor==null){ this.manageExecutor=true; this.taskExecutor=this.createDefaultTaskExecutor(); } if(this.subscriptionExecutor==null){ this.subscriptionExecutor=this.taskExecutor; } this.initialized=true; } protectedTaskExecutorcreateDefaultTaskExecutor(){ StringthreadNamePrefix=this.beanName!=null?this.beanName+"-":DEFAULT_THREAD_NAME_PREFIX; returnnewSimpleAsyncTaskExecutor(threadNamePrefix); }
afterPropertiesSet()这个方法熟悉吧,这个方法将在所有的属性被初始化后调用(InitializingBean接口细节这里不再赘述)。
所以如果用户没有定义springSessionRedisTaskExecutor,Springsession将调用createDefaultTaskExecutor()方法创建SimpleAsyncTaskExecutor线程池。而这个“线程池”处理任务时每次都创建新的线程。所以你会发现很多个redisMessageListenerContailner-X线程。
总结
以上所述是小编给大家介绍的解决Springsession(redis存储方式)监听导致创建大量redisMessageListenerContailner-X线程问题,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!