待解決的問題
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