org.springframework.boot
spring-boot-starter-test
test
@RunWith(SpringJUnit4ClassRunner.class) //默认
@SpringBootTest(classes = AsyncApplication.class) //此处括号内的classes改为自己的application类
测试一 :首先是测试通过spring注入获取的service @Async注解生不生效
@Service(value = "myService")
public class MyServiceImpl implements MyService {
@Autowired
private UserMapper userMapper;
@Autowired
private CoinMapper coinMapper;
/**
* 注意: Async注解返回类型被限制为{@code void}或{@link java.util.concurrent.Future}
* 第一种情况 不接收返回值
*/
@Async
public void task1(){
long s = System.currentTimeMillis();
System.out.println("当前线程:"+Thread.currentThread().getName()+"启动");
System.out.println("任务一执行开始");
//获取用户积分
int userCoinNum = coinMapper.getUserCoinNum(1);
System.out.println("用户积分:"+userCoinNum);
long e = System.currentTimeMillis();
System.out.println("任务一执行结束,总耗时:"+(e-s)+"ms");
}
/**
* 获取用户信息 并返回
* @return
*/
@Async
public Future<User> task2(){
long s = System.currentTimeMillis();
System.out.println("当前线程:"+Thread.currentThread().getName()+"启动");
System.out.println("任务二执行开始");
User user = userMapper.getUserById(1);
System.out.println("用户信息:"+user.toString());
long e = System.currentTimeMillis();
System.out.println("任务二执行结束,总耗时:"+(e-s)+"ms");
return new AsyncResult<>(user);
}
}
//test类
/**
* 通过spring调用service进行测试
*/
@Test
public void test1() throws ExecutionException, InterruptedException {
long s = System.currentTimeMillis();
myService.task1();
Future<User> objectFuture = myService.task2();
System.out.println("接收的用户信息:"+objectFuture.get());
long e = System.currentTimeMillis();
System.out.println("test1总耗时"+(e-s)+"ms");
}
执行结果
可以看出当前异步已经生效
开始测试-------------------------
当前线程:task-1启动
当前线程:task-2启动
任务二执行开始
任务一执行开始
2019-10-22 10:26:18.999 INFO 2568 --- [ task-2] com.alibaba.druid.pool.DruidDataSource : {dataSource-1} inited
用户信息:User{id=1, nickname='凉城', username='liangcheng', password='123456', regTime=Thu Sep 19 13:05:25 GMT+08:00 2019, coinNum=0}
任务二执行结束,总耗时:294ms
用户积分:1000
任务一执行结束,总耗时:294ms
接收的用户信息:User{id=1, nickname='凉城', username='liangcheng', password='123456', regTime=Thu Sep 19 13:05:25 GMT+08:00 2019, coinNum=0}
test1总耗时299ms
结束测试-------------------------
第二种结果
由于第一个不需要接收返回值 所有有时候会发生test方法已经执行结束 但是线程一还未结束的情况
线程二是一定会执行完毕的 因为Future 的get()方法有锁 当线程而未执行结束 主线程无法拿取返回值的时候就会锁住所有线程进行等待
直到线程二执行完毕才会解锁
开始测试-------------------------
当前线程:task-1启动
任务一执行开始
当前线程:task-2启动
任务二执行开始
2019-10-22 10:36:25.079 INFO 12380 --- [ task-2] com.alibaba.druid.pool.DruidDataSource : {dataSource-1} inited
用户信息:User{id=1, nickname='凉城', username='liangcheng', password='123456', regTime=Thu Sep 19 13:05:25 GMT+08:00 2019, coinNum=0}
任务二执行结束,总耗时:247ms
接收的用户信息:User{id=1, nickname='凉城', username='liangcheng', password='123456', regTime=Thu Sep 19 13:05:25 GMT+08:00 2019, coinNum=0}
test1总耗时252ms
结束测试-------------------------
用户积分:1000
任务一执行结束,总耗时:250ms
测试二 :通过本地实例化得到的service进行测试
由于是本地实例化的MyServiceImpl 无法获取到注入的mapper,把方法稍微改造下
//task1方法修改为以下
@Async
public void task1(){
long s = System.currentTimeMillis();
System.out.println("当前线程:"+Thread.currentThread().getName()+"启动");
System.out.println("任务一执行开始");
// //获取用户积分
// int userCoinNum = coinMapper.getUserCoinNum(1);
// System.out.println("用户积分:"+userCoinNum);
//获取随机数
int num =(int)(Math.random()*100);
String msg ="随机数"+num;
System.out.println(num);
//由于时间太短可能看不出效果 这里让线程休眠100ms
Thread.sleep(100);
long e = System.currentTimeMillis();
System.out.println("任务一执行结束,总耗时:"+(e-s)+"ms");
}
//新增task3方法
@Async
public Future<Integer> task3() {
long s = System.currentTimeMillis();
System.out.println("当前线程:"+Thread.currentThread().getName()+"启动");
System.out.println("任务二执行开始");
//获取随机数
int num =(int)(Math.random()*100);
String msg ="随机数"+num;
System.out.println(num);
long e = System.currentTimeMillis();
System.out.println("任务二执行结束,总耗时:"+(e-s)+"ms");
return new AsyncResult<>(num);
}
/**
* 通过本地实例调用MyServiceImpl
*/
@Test
public void test2() throws ExecutionException, InterruptedException {
MyServiceImpl myServiceImpl1 = new MyServiceImpl();
long s = System.currentTimeMillis();
myServiceImpl1.task1();
Future<Integer> integerFuture = myServiceImpl1.task3();
System.out.println("接收的用户信息:"+integerFuture.get());
long e = System.currentTimeMillis();
System.out.println("test2总耗时"+(e-s)+"ms");
}
结果
@Async核心就是创建一个线程去执行任务 实现多线程执行
开始测试-------------------------
当前线程:main启动
任务一执行开始
30
任务一执行结束,总耗时:102ms
当前线程:main启动
任务二执行开始
43
任务二执行结束,总耗时:0ms
接收的用户信息:43
test2总耗时104ms
结束测试-------------------------
不使用public的方法无法使用@Async,直接提示methods annotated with @Async must be ovverridable
创建test3测试之前task1
/**
* 测试@Async注解方法的类中调用@Async方法
*/
@Test
public void test3() throws ExecutionException, InterruptedException {
long s = System.currentTimeMillis();
myService.task1();
// myService.task4();
long e = System.currentTimeMillis();
System.out.println("test3总耗时"+(e-s)+"ms");
}
结果 @Async注解生效task1为异步执行
开始测试-------------------------
test3总耗时5ms
结束测试-------------------------
当前线程:task-1启动
任务一执行开始
33
新增方法task4调用task1
public void task4() throws InterruptedException {
long s = System.currentTimeMillis();
System.out.println("任务四执行开始");
System.out.println("开始调用任务一----------");
this.task1();
System.out.println("调用任务一结束----------");
long e = System.currentTimeMillis();
System.out.println("任务四执行结束,总耗时:"+(e-s)+"ms");
}
//tast方法
/**
* 测试@Async注解方法的类中调用@Async方法
*/
@Test
public void test3() throws ExecutionException, InterruptedException {
long s = System.currentTimeMillis();
// myService.task1();
myService.task4();
long e = System.currentTimeMillis();
System.out.println("test3总耗时"+(e-s)+"ms");
}
结果:task1方法@Async注解失效 当前调用为main线程执行
开始测试-------------------------
任务四执行开始
开始调用任务一----------
当前线程:main启动
任务一执行开始
74
任务一执行结束,总耗时:101ms
调用任务一结束----------
任务四执行结束,总耗时:101ms
test3总耗时102ms
结束测试-------------------------
代码地址:https://gitee.com/liangchenghaoshuai/Async