记一次踩坑 restTemplate, threadPoolTaskExecutor

 

背景:

用户添加一个ak,需要向若干个url发送请求,因此需要采用多线程的方式提高效率

方案:

采用spring提供的ThradPoolTaskExecutor类创建线程池,使用@Async创建异步任务,@EnableAsync开启异步,部分代码如下所示:

 

 
@Configuration
 @EnableAsync
 public class ThreadPoolConfig {
     private static final int corePoolSize = 10;             // 核心线程数(默认线程数)
     private static final int maxPoolSize = 100;             // 最大线程数
     private static final int keepAliveTime = 10;            // 允许线程空闲时间(单位:默认为秒)
     private static final int queueCapacity = 200;           // 缓冲队列数
     private static final String threadNamePrefix = "Async-Service-"; // 线程池名前缀
 ?
     @Bean("taskExecutor") // bean的名称,默认为首字母小写的方法名
     public ThreadPoolTaskExecutor getAsyncExecutor(){
         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
         executor.setCorePoolSize(corePoolSize);
         executor.setMaxPoolSize(maxPoolSize);
         executor.setQueueCapacity(queueCapacity);
         executor.setKeepAliveSeconds(keepAliveTime);
         executor.setThreadNamePrefix(threadNamePrefix);
 ?
         // 线程池对拒绝任务的处理策略
         executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
         // 初始化
         executor.initialize();
         return executor;
     }
 }
 ?
 @Component
 public class Agent{
     @Autowired
     private RestTemplate restTemplate;
     
     @Async
     public void sendMsg(Ak ak, String url) {
         restTemplate.exchange(..);
         logger.info("向{}发送成功", url);
     }
 }
 ?
 @Component
 public class MyController{
     public void handleMsg() {
         for(String url : urls) {
             agent.sendMsg();
         }
     }
 }

 

 

问题:

控制台不输出restTemplate.execute()的日志,debug也找不到对应的问题

踩坑:

RestTemplate采用的是同步方式,不能执行异步任务

这种情况下,使用同步比较好,可以使用Feature feature = executor.submit(Runnable task)

 

如果还是想要用异步的方式该怎么办呢?

spring提供了AsyncRestTemplate提供异步请求方式,只需要将restTemplate更换为asyncRestTemplate即可

扩展:

1、execute()和submit()二者的区别

后者有返回值,可以获得执行结果相关信息.get()方法会阻塞当前线程直到任务完成,使用get(long timeout, TimeUnit unit)设置超时时间,阻塞线程一段时间后立即返回(任务可能没完成)

 
threadPool.execute(
     ()->{
         //TODO task
     });
 ?
 Future<Object> future = threadPool.submit(){
     ()->{
         //TODO
     };   
 }
 try{
     Object obj = future.get();
 }catch(Exception ex) {
     // 
 }finally{
     // 
 }

 

 

2、什么场景下分别使用异步和同步?

 1、不涉及共享资源,或对共享资源只读,即非互斥操作
 2、没有时序上的严格关系
 3、不需要原子操作,或可以通过其他方式控制原子性
 4、常用于IO操作等耗时操作,因为比较影响客户体验和使用性能
 5、不影响主线程逻辑
 ?
 同步的好处:
 1、同步流程对结果处理通常更为简单,可以就近处理。
 2、同步流程对结果的处理始终和前文保持在一个上下文内。
 3、同步流程可以很容易捕获、处理异常。
 4、同步流程是最天然的控制过程顺序执行的方式。  
 异步的好处:
 1、异步流程可以立即给调用方返回初步的结果。
 2、异步流程可以延迟给调用方最终的结果数据,在此期间可以做更多额外的工作,例如结果记录等等。
 3、异步流程在执行的过程中,可以释放占用的线程等资源,避免阻塞,等到结果产生再重新获取线程处理。
 4、异步流程可以等多次调用的结果出来后,再统一返回一次结果集合,提高响应效率。

总结:

【1】这种就属于积累性的问题,多看多想

【2】返璞归真,去掉重重封装,从原始的功能实现出发

 

记一次踩坑 restTemplate, threadPoolTaskExecutor

上一篇:CRM系统在电商企业的应用


下一篇:React学习(三)----- 组件的生命周期