您的位置 首页 > 数码极客

如何监视异步方法时间c

先说一下异步方法的使用场景。根本目的肯定还是为了节省时间。

1、子流程不影响主流程。例如记录日志,发送短信验证码等,主流程不关心这些子流程的结果,或者说默认这些子流程的结果一定正常——如果不正常则启动自己的补偿机制。

2、需要子流程返回结果,但各个子流程相互不依赖。例如已知用户ID,用户的经纬度,通过三个HTTP请求,分别获取用户详细信息、用户订单列表、经纬度所在城市。完全没必要串行。

一、简单开启异步

关键注解:@EnableAsync、@Async

开启CGLIB代理:

@EnableAsync默认是关闭的,使用JDK的代理,与CGLIB代理的区别我想大家应该都懂,不多说了。

@SpringBootApplication @EnableAsync public class SpringBootDemoApplication { public static void main(String[] args) { S, args); } }@Service public class TaskService implements ITaskService { //接口省略 @Async @Override public void testAsync1() { try { T(2000); } catch (InterruptedException e) { e.printStackTrace(); } Sy("异步任务执行完毕"); } }

Controller调用:

@RequestMapping("/async") public DefaultResult<UserResult> async() throws InterruptedException, ExecutionException { (); UserResult ur = new UserResult(); ur.setId(111); ur.setUserName("测试异步"); DefaultResult<UserResult> result = new DefaultResult<UserResult>(); re(ur); Sy("Controller执行完毕"); return result; }

结果就不放了,页面会很快展示JSON串,后台日志“Controller执行完毕”一定在“异步任务执行完毕”后面。


二、返回结果的异步

@Async @Override public Future<String> asyncGetResult1() { try { T(2000); } catch (InterruptedException e) { e.printStackTrace(); } Sy("返回结果A"); return new AsyncResult<String>("结果A"); } @Async @Override public Future<String> asyncGetResult2() { try { T(2000); } catch (InterruptedException e) { e.printStackTrace(); } Sy("返回结果B"); return new AsyncResult<String>("结果B"); }

Controller调用​:

@RequestMapping("/async") public DefaultResult<UserResult> async() throws InterruptedException, ExecutionException { (); Future<String> r1=(); Future<String> r2=(); UserResult ur = new UserResult(); ur.setId(111); ur.setUserName()+":"+r2.get()); DefaultResult<UserResult> result = new DefaultResult<UserResult>(); re(ur); Sy("Controller执行完毕"); return result; }

结果如图​:



可以看到日志打印的是乱序的,如果testAsync1()设置的休眠时间长一点,肯定会在“Controller执行完毕”后打印​日志。


三、自定义线程池

大家可以看@EnableAsync源代码的注释,Spring 会去找实现了TaskExecutor的线程池定义Bean、或者名为“taskExecutor”的Executor类​。如果都没有,则使用SimpleAsyncTaskExecutor——这个线程池,叫它线程池都对不起线程池的“池”字​。每过来一个请求,就创建一个线程,请求完毕就销毁​,​我们用这玩意儿干嘛!

所以还是要自己配置一下​。

配置文件​:

#短信线程池配置

​配置类:

public class GlobalAsynccfg { /** * 核心线程数 */ private Integer corePoolSize = 5; /** * 最大线程数 */ private Integer maxPoolSize = 10; /** * 空闲线程存活时间 */ private Integer keepAliveSeconds = 60; /** * 等待队列长度 */ private Integer queueCapacity = 15; //省略Get、Set }

短信线程池​配置类:

@Component @ConfigurationProperties(prefix=";) public class SmsThreadPoolCfg extends GlobalAsyncCfg {}

​Executor配置类:

@Configuration public class GlobalExecutorCfg { private SmsThreadPoolCfg smsThreadPoolCfg; public GlobalExecutorCfg(SmsThreadPoolCfg smsThreadPoolCfg) { super(); = smsThreadPoolCfg; } @Bean(name = "smsExecutor") public Executor getSmsExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); execu()); execu()); execu()); execu()); execu("SmsExecutor-"); return executor; } }

接着修改我们的异步方法​:

@Async("smsExecutor") @Override public void testAsync1() { try { T(2000); } catch (InterruptedException e) { e.printStackTrace(); } logger.info("异步任务执行完毕"); }

其他两个方法代码省略。

​执行结果日志:


大家注意输出的“SmsExecutor-1”等字样。


四、配置多个线程池​

第三节我的代码都带上了“sms”的字样,为的就是本节​内容。

假设我们有一个请求,需要异步调用以下接口​:

1、通过HTTP请求,​获取用户信息。

2、通过Kafka发送消息给消息队列,供别的模块处理相关流程​。

3、向DB​插入用户访问日志。

4、​发送短信验证码。

如果这些异步调用共用一个线程池的话,如果其中一个方法比较耗时,那就很快占满线程池,导致其他执行很快的方法无法执行​。

所以我们建议不同的业务,使用​不同的线程池。

配置文件​:

#短信线程池配置 #日志线程池配置 log. log. log. log.

增加​日志线程池配置类:

@Component @ConfigurationProperties(prefix = "log.threadpool") public class LogThreadPoolCfg extends GlobalAsyncCfg {}

修改Executor配置类:

@Configuration public class GlobalExecutorCfg { private SmsThreadPoolCfg smsThreadPoolCfg; private LogThreadPoolCfg logThreadPoolCfg; public GlobalExecutorCfg(SmsThreadPoolCfg smsThreadPoolCfg, LogThreadPoolCfg logThreadPoolCfg) { super(); = smsThreadPoolCfg; = logThreadPoolCfg; } @Bean(name = "smsExecutor") public Executor getSmsExecutor() { return (smsThreadPoolCfg, "SmsExecutor-"); } @Bean(name = "logExecutor") public Executor getLogExecutor() { return (logThreadPoolCfg, "LogExecutor-"); } private Executor buildExecutor(GlobalAsyncCfg cfg, String prefix) { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); execu()); execu()); execu()); execu()); execu(prefix); return executor; } }

修改异步方法​:

@Async("logExecutor") @Override public void testAsync1() { try { T(2000); } catch (InterruptedException e) { e.printStackTrace(); } logger.info("异步任务执行完毕"); }

结果​:


注意日志里面的logExecutor和SmsExecutor,这样不同业务使用不同线程池,一旦出现问题既方便排查,也做了业务隔离。​

责任编辑: 鲁达

1.内容基于多重复合算法人工智能语言模型创作,旨在以深度学习研究为目的传播信息知识,内容观点与本网站无关,反馈举报请
2.仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证;
3.本站属于非营利性站点无毒无广告,请读者放心使用!

“如何监视异步方法时间c”边界阅读