springboot async注解,java async注解
00-1010后台异步调用@Async简介在Spring中启用@Async示例1:基本用法示例2:在同一个类中调用异步方法示例3:异步方法是静态方法示例4:在方法级修改默认执行器补充:Java中异步注释@Async的陷阱总结
目录
一般来说,Java中的方法调用都是同步调用。比如在方法A中调用方法B,方法B被方法A调用后,方法A执行并返回后可以继续执行。其中一个容易出现的问题是,如果B方法执行时间较长,可能会导致调用a的请求响应较慢,要解决这个问题,可以使用Spirng的annotation @Async来异步处理这个问题,当然也有其他多线程的方式来解决这类问题。本文主要分析@Async在解决此类问题中的用法以及具体实例。
00-1010比如方法A调用方法B,如果B是异步方法,那么调用方法B之后,方法A就不用等待方法B的执行完成,而是直接下去继续执行其他代码。
00-1010在Spring中,用@Async标记方法可以使其成为异步方法。当调用这些方法时,它们将在一个独立的线程中执行,调用方不必等待方法完成。
00-1010使用@EnableAsync
@ Slf4j @ Spring boot application @ components can(base packages={ com . kaesar . Spring })@ enable async//打开异步调用公共类应用程序{ public static void main(string[]args){ log . info( Spring boot starts . );application context CTX=spring application . run(application . class,args);string[]active profiles=CTX . get environment()。getActiveProfiles();For(字符串配置文件:活动配置文件){log.info(当前环境为: 配置文件);} log.info(春季启动成功.);}}
00-1010将@Async注释添加到方法中
/* * *异步方法*默认情况下,Spring使用SimpleAsyncTaskExecutor来执行这些异步方法(这个Executor对线程数量没有限制)。*此默认值可以从两个级别覆盖:*方法级别*应用程序级别*/@ async public void test 2(){ try { log . info(thread . current thread()。“睡眠前,测试2中的getname()”);线程.睡眠(2000年);log.info(Thread.currentThread()。睡眠后,测试2中的getName());} catch(interrupted exception e){ log . error( sleep error。);}}调用异步方法
/* * *调用不同类的异步方法*/public void func 1(){ log . info( before Call async function。);async service . test 2();log.info(调用异步函数后);试试{ thread . sleep(3000);} catch(interrupted exception e){ log . error( sleep error。);} log.info(func end。);}
从执行结果可以看出,调用异步方法test2后,主线程中的func1方法不需要等待test2方法完成,直接执行下面的代码。
00-1010方法func2与上面的异步方法test2方法在同一个类中。
p>
从执行结果可知,main线程中的func2方法在调用异步方法test2方法后,等待test2方法执行完后,才继续往后执行。
示例三:异步方法是static方法
异步方法test3是一个static方法
/** * 异步方法不能是 static 方法,不然注解失效 */@Asyncpublic static void test3() { try { log.info(Thread.currentThread().getName() + " in test3, before sleep."); Thread.sleep(2000); log.info(Thread.currentThread().getName() + " in test3, after sleep."); } catch (InterruptedException e) { log.error("sleep error."); }}
调用test3的方法
/** * 调用不同类的异步方法,异步方法是 static 方法 */public void func3() { log.info(Thread.currentThread().getName() + ": before call async function."); AsyncService.test3(); log.info(Thread.currentThread().getName() + ": after call async function."); try { Thread.sleep(3000); } catch (InterruptedException e) { log.error("sleep error."); } log.info(Thread.currentThread().getName() + ": func end.");}
执行结果。可以看出在static方法上添加@Async注解,当调用该方法时并没有新启用一个线程单独执行,而是按顺序执行代码,说明异步无效。
示例四:在方法级别上修改默认的执行器
自定义一个线程池执行器代替默认的执行器
自定义的线程池执行器
import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.task.AsyncTaskExecutor;import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;/** * 自定义线程池 */@Configurationpublic class AsyncConfig { private static final int MAX_POOL_SIZE = 10; private static final int CORE_POOL_SIZE = 5; @Bean("asyncTaskExecutor") public AsyncTaskExecutor asyncTaskExecutor() { ThreadPoolTaskExecutor asyncTaskExecutor = new ThreadPoolTaskExecutor(); asyncTaskExecutor.setMaxPoolSize(MAX_POOL_SIZE); asyncTaskExecutor.setCorePoolSize(CORE_POOL_SIZE); asyncTaskExecutor.setThreadNamePrefix("async-task-thread-pool-"); asyncTaskExecutor.initialize(); return asyncTaskExecutor; }}
异步方法上使用自定义的执行器
/** * 在方法级别上修改默认的执行器 */@Async("asyncTaskExecutor")public void test4() { try { log.info(Thread.currentThread().getName() + ": in test4, before sleep."); Thread.sleep(2000); log.info(Thread.currentThread().getName() + ": in test4, after sleep."); } catch (InterruptedException e) { log.error("sleep error."); }}
调用test4异步方法
/** * 调用不同类的异步方法 */public void func4() { log.info(Thread.currentThread().getName() + ": before call async function."); asyncService.test4(); log.info(Thread.currentThread().getName() + ": after call async function."); try { Thread.sleep(3000); } catch (InterruptedException e) { log.error("sleep error."); } log.info(Thread.currentThread().getName() + ": func end.");}
从执行结果可以看出,@Async注解声明使用指定的自定义的异步执行器,已经替换了默认的执行器。而且调用异步方法的main线程没有等待异步方法的执行。
说明:新建自定义的执行器后,注解@Async默认就会替换成自定义的执行器,所以在@Async注解上可以不用指定。
(1.01^{365} ≈ 37.7834343329)(0.99^{365} ≈ 0.02551796445)相信坚持的力量!
补充:Java中异步注解@Async的陷阱
或许,你在Java后端添加异步过程时会这样处理,然后摇摇大摆、灰溜溜地闪,而实际的运行结果却并不是我们期望的那样。那么,现在就将试验结果记录如下,以便少走弯路。
(一)在Controller层的公开接口直接添加@Async注解
当前端调用该种接口时会立刻结束,意味着开始即结束,不会在乎该异步接口返回的数据,其实这种接口只适合前端下发命令,后续就不管后端的处理流程了,也不需要后端返回的对象。
(二)在Controller层的私有接口直接添加@Async注解
这种情况是,前端调用后端的公开接口并等待该接口返回,此时在该接口中调用了该层的添加了@Async注解的私有方法,也许你期待的是让后端接口立刻返回,让具体的处理过程放在@Async注解的私有函数中,可事实并没有达到你的效果,添加了@Async注解的私有函数依旧是同步过程,即使你在Controller层的类前面添加了@EnableAsync注解,也无济于事;所以,这种方式达不到异步的效果。我们可以通过日志来验证该过程,如下图所示:
在上图中,我们看到先进入Controller层公开接口,然后进入带有@Async注解的私有方法,接着跳出,最后又回到Controller层公开接口,整个流程就是同步过程,此时的@Async注解没有效果。
(三)在Service层的公开接口直接添加@Async注解
在Controller层提供同步流程的接口,只是在该层中会调用Service层的异步接口,只需要在需要用异步流程完成任务的接口上方添加@Async注解即可,这种策略是可以实现我们的异步过程的,我们还是通过日志来验证该流程,如下图所示:
在上图中,我们看到流程首先进入Controller层,然后立即跳出了Controller层,而Service层的异步接口就是后续完成的任务了,这样的流程已达到我们想要的异步过程了。
总结
到此这篇关于Java中@Async的基本用法和示例的文章就介绍到这了,更多相关java@Async的用法内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。