这是我参与8月更文挑战的第8天,活动详情查看:8月更文挑战
先简单介绍下同步和异步的概念:
同步:按顺序执行
异步:同时执行
在Java程序中,大部分代码基本都是同步执行的,如果程序使用异步执行的话,可以大大提高执行的效率。一般情况下,我们会使用多线程、中间件、还有@Async来实现程序的异步执行。
@Async
spring 3.x之后,就内置了@Async,下面直接来看如何使用@Async
- 创建异步配置类
@EnableAsync 开启异步支持 配置线程池相关属性 可以自定义多个线程池,通过@Async("线程池名称")指定线程池
import java.util.concurrent.ThreadPoolExecutor;
/**
* @author CTW
*/
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 设置核心线程数
executor.setCorePoolSize(5);
// 设置最大线程数
executor.setMaxPoolSize(10);
// 设置队列容量
executor.setQueueCapacity(20);
// 设置线程活跃时间(秒)
executor.setKeepAliveSeconds(60);
// 设置默认线程名称
executor.setThreadNamePrefix("Test-Async");
// 设置拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
return executor;
}
}
- @Async注解的使用
两种情况:1.方法无返回,2.方法有返回
@Async 可以写在接口上,也可以写在实现类上
- 无返回
@Async
public void testAsync1() {
long startTime = System.currentTimeMillis();
try {
//模拟耗时
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
System.out.println(Thread.currentThread().getName() + ":void testAsync1(),耗时:" + (endTime - startTime));
}
- 有返回
@Override
@Async
public Future<String> testAsync4() {
long startTime = System.currentTimeMillis();
try {
//模拟耗时
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
return new AsyncResult<>("testAsync4:耗时:" + (endTime - startTime));
}
- 创建接口进行测试(无返回/有返回方法的调用及写法)
调用无返回
@GetMapping("testAsync")
public String testAsync() {
asyncService.testAsync1();
return "testAsync--请求成功!";
}
可以看到调用无返回方法打印的耗时
调用有返回
@GetMapping("testAsync2")
public String testAsync2() throws ExecutionException, InterruptedException {
Future<String> stringFuture = asyncService.testAsync4();
return "testAsync--请求成功!" + stringFuture.get();
}
可以看到调用有返回方法返回的耗时
- 异步执行多个方法
Service
@Override
@Async
public Future<String> testAsync4() {
long startTime = System.currentTimeMillis();
try {
//模拟耗时
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
return new AsyncResult<>("testAsync4:耗时:" + (endTime - startTime));
}
@Override
@Async
public Future<String> testAsync5() {
long startTime = System.currentTimeMillis();
try {
//模拟耗时
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
return new AsyncResult<>("testAsync5:耗时:" + (endTime - startTime));
}
@Override
@Async
public Future<String> testAsync6() {
long startTime = System.currentTimeMillis();
try {
//模拟耗时
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
return new AsyncResult<>("testAsync6:耗时:" + (endTime - startTime));
}
Controller
@GetMapping("testAsync4")
public String testAsync4() throws ExecutionException, InterruptedException {
long startTime = System.currentTimeMillis();
Future<String> stringFuture = asyncService.testAsync4();
Future<String> stringFuture1 = asyncService.testAsync5();
Future<String> stringFuture2 = asyncService.testAsync6();
System.out.println(stringFuture.get());
System.out.println(stringFuture1.get());
System.out.println(stringFuture2.get());
long endTime = System.currentTimeMillis();
System.out.println("请求成功!总耗时:" + (endTime - startTime));
return "请求成功!总耗时:" + (endTime - startTime);
}
可以看到调用的方法是同步执行的
- 如果在主线程操作返回值对象,主线程会等待,还是顺序执行
@GetMapping("testAsync4")
public String testAsync4() throws ExecutionException, InterruptedException {
long startTime = System.currentTimeMillis();
Future<String> stringFuture = asyncService.testAsync4();
System.out.println(stringFuture.get());
Future<String> stringFuture1 = asyncService.testAsync5();
Future<String> stringFuture2 = asyncService.testAsync6();
System.out.println(stringFuture1.get());
System.out.println(stringFuture2.get());
long endTime = System.currentTimeMillis();
System.out.println("请求成功!总耗时:" + (endTime - startTime));
return "请求成功!总耗时:" + (endTime - startTime);
}
先执行testAsync4()拿到返回值,再执行testAsync5()、testAsync6()
大家一定要注意先调用完方法以后再操作返回对象,以免造成方法是同步执行的。
本篇关于@Async的介绍及使用先到这里,主要是介绍Controller层如何异步调用Service层,后续介绍下Service如何异步调用Dao层,持续更新