关系经济人类预测化学自然
中准网
自然科学
知识物理
化学生物
地理解释
预测理解
本质社会
人类现象
行为研究
经济政治
心理结构
关系指导
人文遗产

SpringBoot中异步线程池Async详解

3月7日 夜未央投稿
  很多业务场景需要使用异步去完成,比如:发送短信通知。要完成异步操作一般有两种:
  1、消息队列MQ
  2、线程池处理。
  我们来看看Spring框架中如何去使用线程池来完成异步操作,以及分析背后的原理。一。Spring异步线程池的接口类:TaskExecutor
  在Spring4中,Spring中引入了一个新的注解Async,这个注解让我们在使用Spring完成异步操作变得非常方便。
  Spring异步线程池的接口类,其实质是java。util。concurrent。Executor
  Spring已经实现的异常线程池:1。SimpleAsyncTaskExecutor:不是真的线程池,这个类不重用线程,每次调用都会创建一个新的线程。2。SyncTaskExecutor:这个类没有实现异步调用,只是一个同步操作。只适用于不需要多线程的地方3。ConcurrentTaskExecutor:Executor的适配类,不推荐使用。如果ThreadPoolTaskExecutor不满足要求时,才用考虑使用这个类4。SimpleThreadPoolTaskExecutor:是Quartz的SimpleThreadPool的类。线程池同时被quartz和非quartz使用,才需要使用此类5。ThreadPoolTaskExecutor:最常使用,推荐。其实质是对java。util。concurrent。ThreadPoolExecutor的包装,
  二、简单使用说明
  Spring中用Async注解标记的方法,称为异步方法。在springboot应用中使用Async很简单:
  1、调用异步方法类上或者启动类加上注解EnableAsync
  2、在需要被异步调用的方法外加上Async
  3、所使用的Async注解方法的类对象应该是Spring容器管理的bean对象;
  启动类加上注解EnableAsync:importorg。springframework。boot。SpringAimportorg。springframework。boot。autoconfigure。SpringBootAimportorg。springframework。scheduling。annotation。EnableASpringBootApplicationEnableAsyncpublicclassCollectorApplication{publicstaticvoidmain(String〔〕args)throwsException{SpringApplication。run(CollectorApplication。class,args);}}
  在需要被异步调用的方法外加上Async,同时类AsyncService加上注解Service或者Component,使其对象成为Spring容器管理的bean对象;importorg。springframework。beans。factory。annotation。Aimportorg。springframework。scheduling。annotation。Aimportorg。springframework。stereotype。Cimportorg。springframework。transaction。annotation。TServiceTransactionalpublicclassAsyncService{AsyncpublicvoidasyncMethod(Strings){System。out。println(receive:s);}publicvoidtest(){System。out。println(test);asyncMethod();同一个类里面调用异步方法}Asyncpublicvoidtest2(){AsyncServiceasyncServicecontext。getBean(AsyncService。class);asyncService。asyncMethod();异步}异布调用返回FutureAsyncpublicFutureStringasyncInvokeReturnFuture(inti){System。out。println(asyncInvokeReturnFuture,parementeri);FutureStry{Thread。sleep(10001);futurenewAsyncResultString(success:i);}catch(InterruptedExceptione){futurenewAsyncResultString(error);}}}异步方法和普通的方法调用相同asyncService。asyncMethod(123);FutureStringfutureasyncService。asyncInvokeReturnFuture(100);System。out。println(future。get());
  如果将一个类声明为异步类Async,那么这个类对外暴露的方法全部成为异步方法。AsyncServicepublicclassAsyncClass{publicAsyncClass(){System。out。println(initAsyncClass);}volatileintindex0;publicvoidfoo(){System。out。println(asyncclassfoo,index:index);}publicvoidfoo(inti){this。System。out。println(asyncclassfoo,index:i);}publicvoidbar(inti){this。System。out。println(asyncclassbar,index:i);}}
  这里需要注意的是:
  1、同一个类里面调用异步方法不生效:原因默认类内的方法调用不会被aop拦截,即调用方和被调用方是在同一个类中,是无法产生切面的,该对象没有被Spring容器管理。即Async方法不生效。
  解决办法:如果要使同一个类中的方法之间调用也被拦截,需要使用spring容器中的实例对象,而不是使用默认的this,因为通过bean实例的调用才会被spring的aop拦截
  本例使用方法:AsyncServiceasyncServicecontext。getBean(AsyncService。class);然后使用这个引用调用本地的方法即可达到被拦截的目的
  备注:这种方法只能拦截protected,default,public方法,private方法无法拦截。这个是springaop的一个机制。
  2、如果不自定义异步方法的线程池默认使用SimpleAsyncTaskExecutor。SimpleAsyncTaskExecutor:不是真的线程池,这个类不重用线程,每次调用都会创建一个新的线程。并发大的时候会产生严重的性能问题。
  3、异步方法返回类型只能有两种:void和java。util。concurrent。Future。
  1)当返回类型为void的时候,方法调用过程产生的异常不会抛到调用者层面,
  可以通过注AsyncUncaughtExceptionHandler来捕获此类异常
  2)当返回类型为Future的时候,方法调用过程产生的异常会抛到调用者层面三、定义通用线程池1、定义线程池
  在SpringBoot主类中定义一个线程池,publicExecutortaskExecutor()方法用于自定义自己的线程池,线程池前缀taskExecutor。如果不定义,则使用系统默认的线程池。SpringBootApplicationpublicclassApplication{publicstaticvoidmain(String〔〕args){SpringApplication。run(Application。class,args);}EnableAsyncConfigurationclassTaskPoolConfig{BeanpublicExecutortaskExecutor1(){ThreadPoolTaskExecutorpoolnewThreadPoolTaskExecutor();pool。setCorePoolSize(5);线程池活跃的线程数pool。setMaxPoolSize(10);线程池最大活跃的线程数pool。setWaitForTasksToCompleteOnShutdown(true);pool。setThreadNamePrefix(defaultExecutor);}Bean(taskExecutor)publicExecutortaskExecutor2(){ThreadPoolTaskExecutorexecutornewThreadPoolTaskExecutor();executor。setCorePoolSize(10);executor。setMaxPoolSize(20);executor。setQueueCapacity(200);executor。setKeepAliveSeconds(60);executor。setThreadNamePrefix(taskExecutor);executor。setRejectedExecutionHandler(newThreadPoolExecutor。CallerRunsPolicy());executor。setWaitForTasksToCompleteOnShutdown(true);executor。setAwaitTerminationSeconds(60);}}}
  上面我们通过ThreadPoolTaskExecutor创建了一个线程池,同时设置了如下参数:
  核心线程数10:线程池创建时初始化的线程数
  最大线程数20:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
  缓冲队列200:用来缓冲执行任务的队列
  允许线程的空闲时间60秒:超过了核心线程数之外的线程,在空闲时间到达之后会被销毁
  线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
  线程池对拒绝任务的处理策略:此处采用了CallerRunsPolicy策略,当线程池没有处理能力的时候,该策略会直接在execute方法的调用线程中运行被拒绝的任务;如果执行程序已被关闭,则会丢弃该任务
  设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean
  设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住
  也可以单独类来配置线程池:importorg。springframework。beans。factory。annotation。Vimportorg。springframework。context。annotation。Bimportorg。springframework。context。annotation。Cimportorg。springframework。scheduling。annotation。EnableAimportorg。springframework。scheduling。concurrent。ThreadPoolTaskEimportjava。util。concurrent。Eimportjava。util。concurrent。ThreadPoolECreatedbyhuangguisuon2020610。ConfigurationEnableAsyncpublicclassMyThreadPoolConfig{privatestaticfinalintCOREPOOLSIZE10;privatestaticfinalintMAXPOOLSIZE20;privatestaticfinalintQUEUECAPACITY200;publicstaticfinalStringBEANEXECUTOR事件和情感接口线程池执行器配置return事件和情感接口线程池执行器beanBean(BEANEXECUTOR)publicExecutorexecutor(){ThreadPoolTaskExecutorexecutornewThreadPoolTaskExecutor();executor。setCorePoolSize(COREPOOLSIZE);executor。setMaxPoolSize(MAXPOOLSIZE);设置队列容量executor。setQueueCapacity(QUEUECAPACITY);设置线程活跃时间(秒)executor。setKeepAliveSeconds(60);executor。setThreadNamePrefix(SEPoolTask);设置拒绝策略executor。setRejectedExecutionHandler(newThreadPoolExecutor。CallerRunsPolicy());executor。initialize();}}2、异步方法使用线程池
  只需要在Async注解中指定线程池名即可ComponentpublicclassTask{默认使用线程池AsyncpublicvoiddoTaskOne()throwsException{System。out。println(开始做任务);longstartSystem。currentTimeMillis();Thread。sleep(random。nextInt(10000));longendSystem。currentTimeMillis();System。out。println(完成任务耗时:(endstart)毫秒);}根据BeanName指定特定线程池Async(taskExecutor)publicvoiddoTaskOne()throwsException{System。out。println(开始做任务);longstartSystem。currentTimeMillis();Thread。sleep(random。nextInt(10000));longendSystem。currentTimeMillis();System。out。println(完成任务耗时:(endstart)毫秒);}}3、通过xml配置定义线程池
  Bean文件配置:springasync。xml
  1。线程的前缀为xmlExecutor
  2。启动异步线程池配置!等价于EnableAsync,executor指定线程池task:annotationdrivenexecutorxmlExecutor!id指定线程池产生线程名称的前缀task:executoridxmlExecutorpoolsize525queuecapacity100keepalive120rejectionpolicyCALLERRUNS
  启动类导入xml文件:SpringBootApplicationImportResource(classpath:asyncspringasync。xml)publicclassAsyncApplicationWithXML{privatestaticfinalLoggerlogLoggerFactory。getLogger(AsyncApplicationWithXML。class);publicstaticvoidmain(String〔〕args){log。info(StartAsyncApplication。。);SpringApplication。run(AsyncApplicationWithXML。class,args);}}
  线程池参数说明
  1。‘id’:线程名称的前缀
  2。‘poolsize’:线程池的大小。支持范围minmax和固定值(此时线程池core和maxsizes相同)
  3。‘queuecapacity’:排队队列长度
  4。‘rejectionpolicy’:对方拒绝的任务处理策略
  5。‘keepalive’:线程保护时间(单位秒)四、异常处理
  上面也提到:在调用方法时,可能出现方法中抛出异常的情况。在异步中主要有有两种异常处理方法:1。对于方法返回值是Futrue的异步方法:
  a)、一种是在调用future的get时捕获异常;
  b)、在异常方法中直接捕获异常2。对于返回值是void的异步方法:通过AsyncUncaughtExceptionHandler处理异常ComponentpublicclassAsyncException{带参数的异步调用异步方法可以传入参数对于返回值是void,异常会被AsyncUncaughtExceptionHandler处理掉paramsAsyncpublicvoidasyncInvokeWithException(Strings){log。info(asyncInvokeWithParameter,parementer{},s);thrownewIllegalArgumentException(s);}异常调用返回Future对于返回值是Future,不会被AsyncUncaughtExceptionHandler处理,需要我们在方法中捕获异常并处理或者在调用方在调用Futrue。get时捕获异常进行处理paramireturnAsyncpublicFutureStringasyncInvokeReturnFuture(inti){System。out。println(asyncInvokeReturnFuture,parementer{},i);FutureStry{Thread。sleep(10001);futurenewAsyncResultString(success:i);thrownewIllegalArgumentException(a);}catch(InterruptedExceptione){futurenewAsyncResultString(error);}catch(IllegalArgumentExceptione){futurenewAsyncResultString(errorIllegalArgumentException);}}}
  实现AsyncConfigurer接口对异常线程池更加细粒度的控制
  a)创建线程自己的线程池
  b)对void方法抛出的异常处理的类AsyncUncaughtExceptionHandlerServicepublicclassMyAsyncConfigurerimplementsAsyncConfigurer{OverridepublicExecutorgetAsyncExecutor(){ThreadPoolTaskExecutorthreadPoolnewThreadPoolTaskExecutor();threadPool。setCorePoolSize(1);threadPool。setMaxPoolSize(1);threadPool。setWaitForTasksToCompleteOnShutdown(true);threadPool。setAwaitTerminationSeconds(6015);threadPool。setThreadNamePrefix(MyAsync);threadPool。initialize();returnthreadP}OverridepublicAsyncUncaughtExceptionHandlergetAsyncUncaughtExceptionHandler(){returnnewMyAsyncExceptionHandler();}自定义异常处理类classMyAsyncExceptionHandlerimplementsAsyncUncaughtExceptionHandler{OverridepublicvoidhandleUncaughtException(Throwablethrowable,Methodmethod,Object。。。obj){System。out。println(Exceptionmessagethrowable。getMessage());System。out。println(Methodnamemethod。getName());for(Objectparam:obj){System。out。println(Parametervalueparam);}}}}五、问题
  上面也提到:如果不自定义异步方法的线程池默认使用SimpleAsyncTaskExecutor。SimpleAsyncTaskExecutor:不是真的线程池,这个类不重用线程,每次调用都会创建一个新的线程。并发大的时候会产生严重的性能问题。
  一般的错误OOM:OutOfMemoryError:unabletocreatenewnativethread,创建线程数量太多,占用内存过大。
  解决办法:一般最好使用自定义线程池,做一些特殊策略,比如自定义拒绝策略,如果队列满了,则拒绝处理该任务。
  原文链接:https:blog。csdn。nethguisuarticledetails106671893
投诉 评论 转载

2022,我希望写得太好了2022,我希望,家人都是健健康康的;家庭都是和和睦睦的;每天都是开开心心的;一直都是快快乐乐的。2022,我希望,生活都是大富大贵的;……金喜善真抗老!大婶年纪穿套装身姿仍窈窕,皮肤像剥了壳的鸡蛋伴随着气温逐渐回升,花样繁多的春装陆续上线,大家对于时尚的热情又攀高峰,要想在人群中穿出脱颖而出的时髦感,这就很考验大家的时尚功底了。初春季节虽说没有冬天那么冷,但是还是早晚气……经济学家是怎么样解释大萧条的?10月10日,2022年诺贝尔经济学奖揭晓。获奖得主是三位美国经济学家,本伯南克、道格拉斯戴蒙德、菲利普迪布维格,他们因为对银行和金融危机的研究而获奖。这三位将分享1000万瑞……瑞典国家游,科普文化知识谈到瑞典,大家的第一印象有可能想到瑞士,但是这是瑞典哦,那么瑞典有哪些有趣的科普小知识了?〔呲牙〕〔微风〕瑞典的首都:斯德哥尔摩。不是斯德哥尔摩密码咯。〔微风〕瑞典……卫子夫服侍汉武帝49年,自杀前留下一封遗书,汉武帝看后怒骂不忧家国任奸臣,骨肉翻为陌路人。巫蛊事行冤莫雪,九层徒筑见无因。《望思台》纵观古今,每一任皇帝的背后都有三宫六院,但三宫六院之中并非都是皇上喜欢的人,只有那么一两位能够得……原神3。5版本榨干钱包的卡池角色返场各位旅行者们,相信大家都很激动和期待吧!万众期待的胡桃夜兰卡池即将就要和我们见面了,最近也是有不少玩家想知道接下来几个版本都会up哪些五星角色,会不会有万叶优菈可莉这些许久未复……大幅度增加单兵负重能力的单兵可变拖车型四足机器人的想法当单兵如果配置四足机器人帮忙运输较重的货物,即便电池技术得到了发展,但是载重能力和续航能力仍然是抛不开的问题。现在也有单兵拖车的设计,但是石子路面,泥泞道路等不适合轮式适合足式……绝了!巴西巨星40岁现状卡洛琳每月获得5万,卡卡迎娶小女友足球助力团巴西足坛有不少优秀的球员不断地涌现出来,其中卡卡的容貌可比潘安,他是巴西足坛史上最靓的一个仔,而他的球技也可以和那些顶级巨星相媲美,不过卡卡的第一段婚姻是失败的……姜文老婆的时尚看不懂!穿一身深蓝色真清纯,但短靴配红袜显腿短在穿搭这件事上,色彩之间的搭配是永恒的主题,想要穿的时髦,首先需要做到的第一步就是要做好色彩之间的搭配,配色用的好,时尚没烦恼。与一些色彩,好像天生就注定是要在一起的,比……年轻人会不会患大肠癌呢?大肠癌有年轻化趋势我国每5分钟就有1人死于大肠癌近年来,大肠癌(包括直肠癌和结肠癌)的发病率逐年上升。数据显示,我国每5分钟就有1人死于大肠癌,绝大多数发现就是中晚……SpringBoot中异步线程池Async详解很多业务场景需要使用异步去完成,比如:发送短信通知。要完成异步操作一般有两种:1、消息队列MQ2、线程池处理。我们来看看Spring框架中如何去使用线程池来完……查出血脂偏高怎么办?这3个方法若能运用好,血脂偷偷降血液状态保持正常,可以在血管中流动速度快,某些部位才不会缺血而引发症状,但是,现在血脂高的人越来越多,血液处于粘稠状态后流动速度慢,会影响器官功能,需要了解改善的措施,通过正确……
重庆百团千企国际市场开拓计划首站累计签约金额3088万美元职场男性健康晚餐有何禁忌身体这里开裂是说明肝脏不好此心安处在家乡荒唐造句用荒唐造句大全故乡依然职业发展与就业创业指导课教学现状的分析及思考九年我多了一份财富十一月文旅资讯汇总预测今年出境旅游人数为2562万2022第一季度高端智能手机份额出炉,苹果碾压国产,华为跌至春雨男女之间难以承受的重
10万能开音乐烤吧吗,费用都有哪些早安暖心话短句正能量早安经典短句子精选伟大发明家,爱迪生名言经典动漫歌曲(分享一些好听的动漫歌曲)掉牙作文三年级十六罗汉赞史上最强败家子败光百亿家产,撩遍好莱坞,晚年借钱住豪华酒店烦人的油性皮肤该怎么护理呢我们当老师《我的反派男友》大结局:2对CP收获幸福,1人身份“洗白”热 不要困在过去要活在春天里户外广告安装合同

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找菏泽德阳山西湖州宝鸡上海茂名内江三亚信阳长春北海西安安徽黄石烟台沧州湛江肇庆鹤壁六安韶关成都钦州