使用异步可以很有效加快我们接口的访问,如A方法执行时间2秒,B方法执行时间2秒,整个接口需要4秒,合理的使用异步可以是该接口达到2秒。
在Spring中,方法上声明了@Async调用就会变成异步,这使得异步编程特别方便。
@Async的使用
模拟数据库使用:
@org.springframework.stereotype.Service
class Service {
/**
* 添加用户模拟延迟
*/
@Async
public Future<Integer> addUser(){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
System.out.println("addUser方法执行完毕!");
return new AsyncResult<Integer>(1);
}
/**
* 添加会员模拟延迟
*/
@Async
public Future<Integer> addMember(){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
System.out.println("addMember方法执行完毕!");
return new AsyncResult<Integer>(1);
}
}
测试调用:
package com.terry.async;
import com.terry.App;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@SpringBootTest(classes = App.class)
public class TestAsync {
@Autowired
private Service service;
@Test
public void testAsync(){
long start = System.currentTimeMillis();
Future<Integer> member = service.addMember();
Future<Integer> user = service.addUser();
try {
System.out.println("结果:" + member.get() + "," + user.get());
long end = System.currentTimeMillis();
System.out.println("接口耗时:" + (end - start));
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
打印输出
方法返回值不是Future
不返回Future会空指针或者是void的情况,整个main方法不会等方法执行完再走下一步,而是直接执行完毕
package com.terry.async;
import com.terry.App;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@SpringBootTest(classes = App.class)
public class TestAsync {
@Autowired
private Service service;
@Test
public void testAsync(){
long start = System.currentTimeMillis();
//Future<Integer> member = service.addMember();
service.addMember();
Integer user = service.addUser(); // 不返回Future会空指针,并且整个main方法不会等方法执行完再走下一步,而是直接执行完毕
System.out.println("结果:," + user);
long end = System.currentTimeMillis();
System.out.println("接口耗时:" + (end - start));
}
}
@org.springframework.stereotype.Service
class Service {
/**
* 添加用户模拟延迟
*/
@Async
// public Future<Integer> addUser(){
public Integer addUser(){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
System.out.println("addUser方法执行完毕!");
// return new AsyncResult<Integer>(1);
return 1;
}
/**
* 添加会员模拟延迟
*/
@Async
public void addMember(){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
System.out.println("addMember方法执行完毕!");
}
}
运行结果如下,可以看到main方法赶在addMember和addUser方法之前执行
@Async失效原因
未添加@EnableAsync注解
需要在启动类或者配置类添加@EnableAsync注解,如下:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@SpringBootApplication
@EnableAsync
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
执行体和调用者在同一个类
因为aop代理的缘故,与Spring声明式事务一个道理,调用者与@Async的方法不能写在同一个类,要拆开写。
方法返回值不是Future
如果你想得到返回值,那么就必须使用Future。如果使用void或者是其它返回值,方法不会等异步方法执行完再走下一步,而是直接执行完毕