@Async注解的用法和例子[TOC]背景通常Java中的方法调用都是同步调用,比如方法A中调用了方法B,那么方法A调用方法B之后,必须等待B方法执行完毕返回,A方法才能继续执行。这样容易出现的一个问题是如果B方法执行时间比较长,可能会导致请求调用A响应慢。为了解决这个问题,可以使用Spirng的注解@Async来异步处理。当然,也会有其他的多线程方式来解决此类问题。本文主要分析@Async在解决这类问题中的用法和具体的例子。异步调用比如方法A调用方法B,如果B是异步方法,方法A调用方法B后,不需要等待方法B完成,直接继续执行其他代码。@Async简介在Spring中,使用@Async标记一个方法可以使该方法成为异步方法。当调用这些方法时,它们将在一个独立的线程中执行,调用者不需要等待方法完成。.使用@EnableAsync@Slf4j@SpringBootApplication@ComponentScan(basePackages={"com.kaesar.spring"})在Spring中启用@Async@EnableAsync//启用异步调用publicclassApplication{publicstaticvoidmain(String[]args){log.info("springboot启动...");ApplicationContextctx=SpringApplication.run(Application.class,args);String[]activeProfiles=ctx.getEnvironment().getActiveProfiles();for(Stringprofile:activeProfiles){log.info("当前环境为:"+profile);}log.info("springboot启动成功...");}}示例1:在基本用法中为方法添加@Async注解/***异步方法*默认情况下,Spring使用SimpleAsyncTaskExecutor来执行这些异步方法(该执行器不限制线程数)。*这个默认值可以从两个级别覆盖:*方法级别*应用程序级别*/@Asyncpublicvoidtest2(){try{log.info(Thread.currentThread().getName()+"intest2,beforesleep.");线程.睡眠(2000);log.info(Thread.currentThread().getName()+"在test2中,睡眠之后。");}catch(InterruptedExceptione){log.error("sleeperror.");}}调用异步方法/***调用不同类的异步方法*/publicvoidfunc1(){log.info("beforecallasyncfunction.");asyncService.test2();log.info("调用异步函数后。");尝试{Thread.sleep(3000);}catch(InterruptedExceptione){log.error("睡眠错误");}log.info("funcend.");}执行结果从执行结果可以看出,主线程中的func1方法调用异步方法test2后,并没有等待test2方法完成执行,直接执行下面的代码。实例2:在同一个类中调用异步方法methodfunc2和在同一个类中调用上面的异步方法test2方法从执行结果可以看出,主线程中的func2方法调用后等待test2方法的执行异步方法test2方法,然后继续执行。示例3:异步方法是静态方法异步方法test3是静态方法/***异步方法不能是静态方法,否则注解无效*/@Asyncpublicstaticvoidtest3(){try{log.info(Thread.currentThread().getName()+"在test3中,在睡眠之前。");线程.睡眠(2000);log.info(Thread.currentThread().getName()+"在test3中,睡眠之后。");}catch(InterruptedExceptione){log.error("睡眠错误");}}调用test3的方法/***调用不同类型的异步方法,异步方法是静态方法*/publicvoidfunc3(){log.info(Thread.currentThread().getName()+":beforecallasync功能。”);异步服务.test3();log.info(Thread.currentThread().getName()+":在调用异步函数之后。");尝试{Thread.sleep(3000);}catch(InterruptedExceptione){log.error("睡眠错误");}log.info(Thread.currentThread().getName()+":funcend.");}执行结果。可以看出,在静态方法上加上@Async注解后,调用该方法时,并没有开启新的线程单独执行,而是顺序执行代码,说明异步无效。示例4:在方法级别修改默认执行器自定义一个线程池执行器来替换默认执行器自定义线程池执行器springframework.core.task.AsyncTaskExecutor;importorg.springframework.scheduling.concurrent.ThreadPoolTask??Executor;/***自定义线程池*/@ConfigurationpublicclassAsyncConfig{privatestaticfinalintMAX_POOL_SIZE=10;privatefinalintCORE_POOL_SIZE=5;@Bean("asyncTaskExecutor")publicAsyncTaskExecutorasyncTaskExecutor(){ThreadPoolTask??ExecutorasyncTaskExecutor=newThreadPoolTask??Executor();asyncTaskExecutor.setMaxPoolSize(MAX_POOL_SIZE);asyncTaskExecutor.setCorePoolSize(CORE_POOL_SIZE);asyncTaskExecutor.setThreadNamePrefix("async-task-thread-pool-");asyncTaskExecutor.initialize();返回异步任务执行器;}}在异步方法上使用自定义执行器/***在方法级别修改默认执行器*/@Async("asyncTaskExecutor")publiccvoidtest4(){try{log.info(Thread.currentThread().getName()+":intest4,beforesleep.");线程.睡眠(2000);log.info(Thread.currentThread().getName()+":在test4中,睡眠之后。");}catch(InterruptedExceptione){log.error("睡眠错误");}}calltest4异步方法/***调用不同类的异步方法*/publicvoidfunc4(){log.info(Thread.currentThread().getName()+":beforecallasyncfunction.");asyncService.test4();log.info(Thread.currentThread().getName()+":在调用异步函数之后。");尝试{线程。睡眠(3000);}catch(InterruptedExceptione){日志。error("睡眠错误");}日志。info(Thread.currentThread().getName()+":funcend.");}从执行结果可以看出,@Async注解声明使用了指定的自定义异步执行器,替换了默认的执行者和调用异步方法的主线程不等待异步方法执行。注意:创建自定义执行器后,注解@Async默认会被自定义执行器替换,所以不需要在@Async注解上指定。$1.01^{365}≈37.7834343329$$0.99^{365}≈0.02551796445$相信坚持的力量!
