来个spring配置类,需要加上@EnableAsync
开启bean方法的异步调用.
package com.javacode2018.async.demo1;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.scheduling.annotation.EnableAsync;
@ComponentScan
@EnableAsync
public class MainConfig1 {
}
测试代码
package com.javacode2018.async;
import com.javacode2018.async.demo1.LogService;
import com.javacode2018.async.demo1.MainConfig1;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.util.concurrent.TimeUnit;
public class AsyncTest {
@Test
public void test1() throws InterruptedException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(MainConfig1.class);
context.refresh();
LogService logService = context.getBean(LogService.class);
System.out.println(Thread.currentThread() + " logService.log start," + System.currentTimeMillis());
logService.log(“异步执行方法!”);
System.out.println(Thread.currentThread() + " logService.log end," + System.currentTimeMillis());
//休眠一下,防止@Test退出
TimeUnit.SECONDS.sleep(3);
}
}
运行输出
Thread[main,5,main] logService.log start,1595223990417
Thread[main,5,main] logService.log end,1595223990432
Thread[SimpleAsyncTaskExecutor-1,5,main]开始记录日志,1595223990443
Thread[SimpleAsyncTaskExecutor-1,5,main]日志记录完毕,1595223992443
前2行输出,可以看出logService.log
立即就返回了,后面2行来自于log方法,相差2秒左右。
前面2行在主线程中执行,后面2行在异步线程中执行。
5、获取异步返回值
用法
若需取异步执行结果,方法返回值必须为Future
类型,使用spring提供的静态方法org.springframework.scheduling.annotation.AsyncResult#forValue
创建返回值,如:
public Future getGoodsInfo(long goodsId) throws InterruptedException {
return AsyncResult.forValue(String.format(“商品%s基本信息!”, goodsId));
}
案例
场景:电商中商品详情页通常会有很多信息:商品基本信息、商品描述信息、商品评论信息,通过3个方法来或者这几个信息。
这3个方法之间无关联,所以可以采用异步的方式并行获取,提升效率。
下面是商品服务,内部3个方法都需要异步,所以直接在类上使用@Async
标注了,每个方法内部休眠500毫秒,模拟一下耗时操作。
package com.javacode2018.async.demo2;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
@Async
@Component
public class GoodsService {
//模拟获取商品基本信息,内部耗时500毫秒
public Future getGoodsInfo(long goodsId) throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(500);
return AsyncResult.forValue(String.format(“商品%s基本信息!”, goodsId));
}
//模拟获取商品描述信息,内部耗时500毫秒
public Future getGoodsDesc(long goodsId) throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(500);
return AsyncResult.forValue(String.format(“商品%s描述信息!”, goodsId));
}
//模拟获取商品评论信息列表,内部耗时500毫秒
public Future<List> getGoodsComments(long goodsId) throws InterruptedException {
TimeUnit.MILLISECONDS.sleep(500);
List comments = Arrays.asList(“评论1”, “评论2”);
return AsyncResult.forValue(comments);
}
}
来个spring配置类,需要加上@EnableAsync
开启bean方法的异步调用.
package com.javacode2018.async.demo2;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.scheduling.annotation.EnableAsync;
@ComponentScan
@EnableAsync
public class MainConfig2 {
}
测试代码
@Test
public void test2() throws InterruptedException, ExecutionException {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(MainConfig2.class);
context.refresh();
GoodsService goodsService = context.getBean(GoodsService.class);
long starTime = System.currentTimeMillis();
System.out.println(“开始获取商品的各种信息”);
long goodsId = 1L;
Future goodsInfoFuture = goodsService.getGoodsInfo(goodsId);
Future goodsDesc