@Async 注解的用法和示例
[TOC]
背景
通常,在Java中的办法调用都是同步调用,比方在A办法中调用了B办法,则在A调用B办法之后,必须期待B办法执行并返回后,A办法才能够持续往下执行。这样容易呈现的一个问题就是如果B办法执行工夫较长,则可能会导致调用A的申请响应缓慢,为了解决这种问题,能够应用Spirng的注解@Async来用异步调用的形式解决,当然也会有别的多线程形式解决此类问题,本文次要剖析@Async在解决此类问题时的用法以及具体的示例。
异步调用
比方办法A调用办法B,如果B是一个异步办法,则A办法在调用B办法之后,不必期待B办法执行实现,而是间接往下继续执行别的代码。
@Async介绍
在Spring中,应用@Async标注某办法,能够使该办法变成异步办法,这些办法在被调用的时候,将会在独立的线程中进行执行,调用者不需期待该办法执行实现。
在Spring中启用@Async
应用@EnableAsync
@Slf4j@SpringBootApplication@ComponentScan(basePackages = {"com.kaesar.spring"})@EnableAsync // 开启异步调用public class Application { public static void main(String[] args) { log.info("spring boot开始启动..."); ApplicationContext ctx = SpringApplication.run(Application.class, args); String[] activeProfiles = ctx.getEnvironment().getActiveProfiles(); for (String profile : activeProfiles) { log.info("以后环境为:" + profile); } log.info("spring boot启动胜利..."); }}
示例一:根本应用形式
在办法上增加@Async注解
/** * 异步办法 * 默认状况下,Spring 应用 SimpleAsyncTaskExecutor 去执行这些异步办法(此执行器没有限度线程数)。 * 此默认值能够从两个层级进行笼罩: * 办法级别 * 利用级别 */@Asyncpublic void test2() { try { log.info(Thread.currentThread().getName() + " in test2, before sleep."); Thread.sleep(2000); log.info(Thread.currentThread().getName() + " in test2, after sleep."); } catch (InterruptedException e) { log.error("sleep error."); }}
调用异步办法
/** * 调用不同类的异步办法 */public void func1() { log.info("before call async function."); asyncService.test2(); log.info("after call async function."); try { Thread.sleep(3000); } catch (InterruptedException e) { log.error("sleep error."); } log.info("func end.");}
执行后果
从执行后果能够看出,main线程中的func1办法在调用异步办法test2后,没有期待test2办法执行实现,间接执行前面的代码。
示例二:在同一个类中调用异步办法
办法func2和下面的异步办法test2办法在同一个类中
从执行后果可知,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$
置信保持的力量!