安庆大理运城常德铜陵江西
投稿投诉
江西南阳
嘉兴昆明
铜陵滨州
广东西昌
常德梅州
兰州阳江
运城金华
广西萍乡
大理重庆
诸暨泉州
安庆南充
武汉辽宁

Springboot异步多线程编程

8月24日 碧落盟投稿
  一、基础知识
  同步:同步就是指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去;
  异步:异步是指进程不需要一直等下去,而是继续执行下面的操作。当有消息返回时系统会通知进程进行处理,这样可以提高执行的效率。
  进程:进程是独立的应用程序,占用cpu资源和物理内存。一个进程包括由操作系统分配的内存空间,包含一个或多个线程;
  线程:线程是进程中虚拟的时间片,一个线程不能独立的存在,它必须是进程的一部分。
  多线程:实际上就是时间片的轮转或者抢占。多线程能满足编写高效率的程序来达到充分利用CPU的目的;二、什么时候用同步异步
  什么时候用同步:如果数据在线程间共享,例如正在写的数据可能被另外一个线程读到,而正在读的数据可能被另外一个线程写到,这些数据是共享的数据。这时就必须进行同步存取操作,否者前后读取的数据就有可能不一致;
  什么时候用异步:调用一个需要花费很长时间来执行的方法的时候,并且不需要让程序等待对方返回,这时就应该使用异步编程;
  必须使用同步的场景举例:
  有一个共享的银行账号,原来里面有余额1000元,现在有两个用户A,B都要进行取钱;
  首先A查询账号剩余1000元,A想要取出200元,A点击取款,系统正在处理取款事项
  紧接着在A取款的过程中B查询同一个账号还有1000元,B也想要取走200元;
  A取完款后剩余800元,正常。而B取完款后理论上应该剩余600元,但是实际上还是剩余800元。这种场景就必须使用同步,而不能使用异步;三、什么时候需要使用多线程
  举个例子:
  假设有个请求,服务端的处理需要执行3个比较耗时的操作:
  1、操作1(200ms)
  2、操作2(200ms)
  3、操作3(200ms)
  单线程总共就需要600ms,但如果把操作1、操作2、操作3分别分给3个线程去做,就只需要200ms了。
  但是假设另外一个请求,服务端的处理也需要执行3个操作:
  1、操作1(10ms)
  2、操作2(10ms)
  3、操作3(400ms)
  单线程总共就需要420ms,这种情况下,即使把操作1、操作2、操作3分别分给3个线程去做,也需要400ms(耗时取决于最慢的那个线程的执行速度)。比起不用单线程,只节省了20ms。但是有可能线程调度切换也要花费个1、2ms。因此,这个方案显得优势就不明显了,还带来程序复杂度提升,不太值得,此时更好的方案是去优化降低操作3的耗时。四、Springboot异步多线程编程实现
  4。1使用idea创建springbootweb项目,工程最终目录结构如下:
  4。2首先创建springboot的线程池配置:
  common包下面创建ExecutorConfig类,用于自定义线程池的相关配置。使用Configuration和EnableAsync这两个注解,表示这是线程池的配置类。ConfigurationEnableAsyncSlf4jpublicclassExecutorConfig{核心线程数(默认线程数)privateintcorePoolSize10;最大线程数privateintmaxPoolSize20;允许线程空闲时间(单位:默认为秒)privatestaticfinalintkeepAliveTime60;缓冲队列大小privateintqueueCapacity10;BeanpublicExecutorasyncServiceExecutor(){log。info(startasyncServiceExecutor);ThreadPoolTaskExecutorexecutornewThreadPoolTaskExecutor();配置核心线程数executor。setCorePoolSize(corePoolSize);配置最大线程数executor。setMaxPoolSize(maxPoolSize);配置空闲时间executor。setKeepAliveSeconds(keepAliveTime);配置队列大小executor。setQueueCapacity(queueCapacity);配置线程前缀名executor。setThreadNamePrefix(asyncservice);rejectionpolicy:当pool已经达到maxsize的时候,如何处理新任务CALLERRUNS:不在新线程中执行任务,而是有调用者所在的线程来执行executor。setRejectedExecutionHandler(newThreadPoolExecutor。CallerRunsPolicy());执行初始化executor。initialize();}}
  4。3service层接口和实现:
  service包下新增server层的接口AsyncService类和对应的实现类AsyncServiceImpl。AsyncService内容如下:publicinterfaceAsyncService{执行异步任务voidexecuteAsync();}
  AsyncServiceImpl类内容如下,注意:
  1。在executeAsync方法上增加注解Async(asyncServiceExecutor);
  2。Async表示使用异步实现方式
  3。括号里的asyncServiceExecutor是前面ExecutorConfig。java中的方法名,表明executeAsync方法使用asyncServiceExecutor方法创建的线程池多线程执行:Slf4jServicepublicclassAsyncServiceImplimplementsAsyncService{异步多线程调用Async(asyncServiceExecutor)publicvoidexecuteAsync(){log。info(startexecuteAsync);try{Thread。sleep(2000);}catch(Exceptione){e。printStackTrace();}log。info(endexecuteAsync);}}
  4。4controller层实现:
  创建HelloController类,新增testhttp接口,调用server层的executeAsync服务。Slf4jRestControllerpublicclassHelloController{AutowiredprivateAsyncServiceasyncS异步多线程调用方法,不用等方法返回结果RequestMapping(test)publicStringtest(){log。info(startsubmit);调用service层的任务asyncService。executeAsync();log。info(endsubmit);}}
  4。5验证效果:
  验证异步效果:
  1。先将ExecutorConfig类下corePoolSize设置为1,表示只用1个线程。然后运行
  2。springboot启动成功后,在浏览器输入:http:localhost:8080test。可以看到虽然我们前面AsyncServiceImpl代码中sleep了2秒,但由于使用的是异步实现,所以接口马上直接先返回了success,而不需要等待2秒后再返回。
  后台日志也能看到,异步接口controller层很快就执行结束,然后service方法继续按代码执行了2秒:
  验证多线程效果:
  1。corePoolSize设置为1时,使用Jmeter同时调用接口:http:localhost:8080test4次;
  2。在springboot的控制台看见日志如下:
  可以看出是1个线程每隔2秒执行完一次startendexecuteAsync,执行4次总共花费了8秒时间;
  3。将corePoolSize设置为10,重启
  4。再次使用Jmeter同时调用接口:http:localhost:8080test4次;
  5。在springboot的控制台看见日志如下:
  可以看出是4个线程同时在执行,执行完4次startendexecuteAsync,总共花费了2秒时间,这就是多线程可以提高程序运行效率的体现。
  4。6获取多线程的返回值:
  Java自jdk1。5以后,提供了java。util。concurrent。Future来获取异步线程返回的结果。主线程会创建一个Future接口的对象,然后启动并发线程,并告诉并发线程,一旦你执行完毕,就把结果存储在这个Future对象里。
  一般情况下,我们会把长时间运行的逻辑放在异步线程中进行处理,这是使用Future接口最理想的场景。主线程只要简单的将异步任务封装在Future里,然后开始等待Future的完成,在这段等待的时间内,可以处理一些其它逻辑,一旦Future执行完毕,就可以从中获取执行的结果并进一步处理。
  AsyncServiceImpl类中增加两个方法:多线程调用并获取回调结果Async(asyncServiceExecutor)publicFutureStringsendMessageAsync1(){log。info(异步发送消息1执行开始);try{Thread。sleep(2000);}catch(InterruptedExceptione){e。printStackTrace();}log。info(异步发送消息1执行结束);returnnewAsyncResult(异步发送消息1);}Async(asyncServiceExecutor)publicFutureStringsendMessageAsync2(){log。info(异步发送消息2执行开始);try{Thread。sleep(2000);}catch(InterruptedExceptione){e。printStackTrace();}log。info(异步发送消息2执行结束);returnnewAsyncResult(异步发送消息2);}
  AsyncService类中增加接口:FutureStringsendMessageAsync1();FutureStringsendMessageAsync2();
  Controller中增加http接口调用:异步多线程调用,但是要等方法回调结果。用多线程,所以只需要2秒RequestMapping(sendMessageAsync)publicStringsendMessageAsync()throwsExecutionException,InterruptedException{System。out。println(开始时间:newDate());FutureStringsendMessageAsync1asyncService。sendMessageAsync1();FutureStringsendMessageAsync2asyncService。sendMessageAsync2();SStringresult1;Stringresult2;while(!(sendMessageAsync1。isDone()sendMessageAsync2。isDone())){System。out。println(String。format(future1issandfuture2iss,sendMessageAsync1。isDone()?done:notdone,sendMessageAsync2。isDone()?done:notdone));Thread。sleep(300);}resultsendMessageAsync1。get();resultsendMessageAsync2。get();System。out。println(结束时间:newDate());
  上面使用的是先调用Future。isDone()判断任务是否完成,再调用Future。get()从完成的任务中获取任务执行的结果。
  也可以直接用Future。get()并设置一个超时时间:RequestMapping(sendMessageAsync)publicStringsendMessageAsync()throwsExecutionException,InterruptedException{System。out。println(开始时间:newDate());FutureStringsendMessageAsync1asyncService。sendMessageAsync1();FutureStringsendMessageAsync2asyncService。sendMessageAsync2();SStringresult1;Stringresult2;通过future。get()方法阻塞性获取执行结果,设置超时时间为3秒,3秒还没获取到值,就超时报错try{result1sendMessageAsync1。get(3000,TimeUnit。MILLISECONDS);}catch(TimeoutExceptione){sendMessageAsync1。cancel(true);log。error(sendMessageAsync1方法超时未返回结果);e。printStackTrace();}try{result2sendMessageAsync2。get(3000,TimeUnit。MILLISECONDS);}catch(TimeoutExceptione){sendMessageAsync2。cancel(true);log。error(sendMessageAsync2方法超时未返回结果);e。printStackTrace();}resultresult1result2;System。out。println(结束时间:newDate());}
  Future。get()方法是一个阻塞方法。如果任务还没执行完毕,那么会一直阻塞直到直到任务完成
  为了防止调用Future。get()方法阻塞当前线程,推荐的做法是先调用Future。isDone()判断任务是否完成,然后再调用Future。get()从完成的任务中获取任务执行的结果。
  因为Future。isDone()和Future。get()的存在,我们就可以在等待任务完成时运行其它一些代码。使用isDone()和get()方法来获取结果,这应该是消费Future最常见的方式。
  针对上面的代码,如果不用isDone(),直接用get(),那么get()阻塞的这2秒内就不能做任何其他事情。而用了whileisDone(),这2秒内则可以做一些其他的事情,比如上面代码中的输出打印一段话。
  运行结果如下:
  虽然sendMessageAsync1和sendMessageAsync2都要2秒时间,由于是多线程并行处理,所以总共只花费了2秒。
  正常的单线程处理:正常的单线程处理,要花4秒RequestMapping(sendmessage)publicStringsendMessage()throwsExecutionException,InterruptedException{System。out。println(newDate());调用service层的任务StringsendMessage1asyncService。sendMessage1();StringsendMessage2asyncService。sendMessage2();SresultsendMessage1sendMessage2;System。out。println(newDate());}
  单线程顺序执行sendMessage1和sendMessage2,每一个方法执行需要2秒,总共就需要4秒才能执行完。
  以上就是本篇文章的全部内容,如果对你有帮助,
  欢迎搜索关注我的微信公众号【程序员杨叔】:测开一枚,持续分享全栈测试知识干货。标签:自动化测试、性能测试、Java、Python、DevOps、CICD、小程序测试、测试工具、测试开发、测试框架平台、测试管理
投诉 评论 转载

APP个人信息保护规范APP开屏弹窗广告专栏语在浙江省通信管理局指导下,浙江省互联网协会APP个人信息保护专委会制作了APP个人信息保护专题公益视频,呼吁行业自觉维护用户合法权益,营造清朗网络空间。目前部……推动智能时代传统产业数字化转型近年来,随着云计算、大数据、物联网等新一代信息技术蓬勃发展,人工智能技术迎来爆发式增长阶段。基于深度学习的人工智能算法在模式识别、自然语言处理等方面的表现开始接近甚至超过人类智……同样是吹风机,3000元的戴森和300百元的国产有什么区别?洗完头发要吹干还是晾干呢?前些年人们普遍喜欢晾干,理由是吹风机会损伤头发。这些年,又开始鼓励大家用吹风机吹干头发因为洗发后头发的毛鳞片是张开的,如果不吹干,会对头发产生损……Springboot异步多线程编程一、基础知识同步:同步就是指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去;异步:异步……花8000买个Surface还是买超级本iPad?如果预算只能8000以下,建议买个常规的电脑就好了,不建议买surface或超极本ipad的组合。surface轻办公还可以,如果作为办公主力,不建议。而由于苹果生态系统的限制……支付宝更新!一键开启海王模式,妹子们要小心了点击右上方关注,第一时间获取科技资讯、技能攻略、产品体验,私信我回复01,送你一份玩机技能大礼包。最近这几个月,国民级App微信一改之前佛系更新画风,更新了不少功能。……面对美制裁,中企霸气反击直接切断美供应链本文原创,禁止搬运和抄袭,违者必究!大洋彼岸的美国,总是喜欢大搞黑手,任凭心意在全球化的市场中指指点点,搅弄浑水。类似将外企拉入黑名单的例子太多了,又有消息传来,称……电量告急!手机一天不到就没电?了解3种原因3个解决办法出门最担心什么?坏天气?站起来?不能叫出租车?他们都没有这些都不是更好!机器!不!电!但是为什么手机耗电这么快呢?各种后台运行的软件偷偷吃你的电……山西智创城金融服务平台启动可实现投保贷典租一体化服务10月6日消息,山西智创城NO。2科技金融服务平台正式启动运行。通过引入金融机构、出台帮扶政策,入驻山西智创城NO。2的小微企业和创业者可以零距离享受点对点金融服务,获得多种方……越南代加工AirPods做工粗糙,不如买这款魔浪耳机,历时三这一次AirPods3发布之后,貌似口碑并没有以前的几款产品好,10月26日是苹果AirPods3无线耳机的发售日,之前在官网上订购的第一批用户已经陆续收到了心仪的耳机。但根据……你踩过互联网消费贷哪些雷?315数字金融消保调查请你发声拿起手机,借贷广告就无孔不入,充斥着衣食住行的各个方面。另一方面,利率过高、费用不透明、存在诱导超前消费等问题,让互联网消费贷款成为消费者投诉的重灾区,金融监管部门也已多次强调……100W给首付OR买电视?今年让你倾家荡产的电视们随着中国家电市场逐渐壮大,各家电厂商对国内市场的重视程度也逐年提高。在刚刚结束的中国家电及消费电子博览会(AWE2019)上,国内外知名家电企业纷纷带来了旗下旗舰产品。但出乎大……
华为EMUI9。1发布神油优化持久流畅在点淘给粉丝发1亿红包,薇娅打响天猫618第一枪企业用电成本降低2030!百度智能云发布零碳园区解决方案马上评运营商电话营销半年不断,骚扰电话为何挂不断?食品接触材料(FCM检测)有害物质迁移测试数读7月全球电动汽车销量出炉,比亚迪再次击败特斯拉外行买苹果内行买小米?这三款机型表示不服,配置强悍价格不贵北京拟叫停面向学龄前儿童培训教育移动应用专家解读都说戒烟难,一周不抽烟与一周不玩手机,如果二选一你会怎么选?问答我搬家了,新能源汽车充电桩该如何迁移?从5399到4199,昔日的A13小机皇彻底让路,果粉不等了荣耀V30pro还值得买吗?

友情链接:中准网聚热点快百科快传网快生活快软网快好知文好找七猫云易事利