解决Spring session(redis存储方式)监听导致创建大量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(redis存储方式)监听导致创建大量redismessagelistenercontailner-x线程问题,希望对大家有所帮助