在Spring中可以使用@Async注解标记类或方法,有@Async注解的类会生成代理对象,代理对象会将有@Async注解的方法(异步方法)放在线程池里面异步执行;
@Async注解的方法返回值类型可以是void,也可以是Future类型,如果是普通类型则获取不到异步执行结果;
Spring默认使用的SimpleAsyncTaskExecutor线程池不会重用线程,并且没有最大线程数的限制,在大并发量的时候存在性能问题,所以Spring使用自定义线程池配合@Async注解一起使用;
一 简单使用
在配置类中添加@EnableAsync注解;
在业务类中需要异步执行的方法上添加@Async注解;
1.1 方法返回值类型是void
java
@Configuration
@EnableAsync
public class CommonConfig {
}
@Service
public class OrderService {
public void printOrderMsgOne() {
try {
// 模拟线程任务执行
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("\t" + Thread.currentThread().getName()
+ " 输出message one...");
}
@Async
public void printOrderMsgTwo() {
try {
// 模拟线程任务执行
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("\t" + Thread.currentThread().getName()
+ " 输出message two...");
}
}
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private OrderService orderService;
@GetMapping("/one")
public String orderOne() {
System.out.println(Thread.currentThread().getName()
+ " 线程开始执行任务...");
System.out.println("输出printOrderMsgOne方法信息: ");
orderService.printOrderMsgOne();
System.out.println("输出printOrderMsgTwo方法信息: ");
orderService.printOrderMsgTwo();
// 模拟线程任务执行
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ " 线程结束执行任务...");
return "success";
}
}
方法执行结果:
http-nio-8081-exec-2 线程开始执行任务...
输出printOrderMsgOne方法信息:
http-nio-8081-exec-2 输出message one...
输出printOrderMsgTwo方法信息:
http-nio-8081-exec-2 线程结束执行任务...
task-1 输出message two...
orderOne方法在http-nio-8081-exec-2线程中执行,printOrderMsgTwo方法在task-1个线程异步执行;
1.2 方法返回值类型是普通类型
java
@Configuration
@EnableAsync
public class CommonConfig {
}
@Service
public class OrderService {
public void printOrderMsgOne() {
try {
// 模拟线程任务执行
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("\t" + Thread.currentThread().getName()
+ " 输出message one...");
}
@Async
public String printOrderMsgTwo() {
try {
// 模拟线程任务执行
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("\t" + Thread.currentThread().getName()
+ " 输出message two...");
return "printOrderMsgTwo successfully";
}
}
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private OrderService orderService;
@GetMapping("/one")
public String orderOne() {
System.out.println(Thread.currentThread().getName()
+ " 线程开始执行任务...");
System.out.println("输出printOrderMsgOne方法信息: ");
orderService.printOrderMsgOne();
System.out.println("输出printOrderMsgTwo方法信息: ");
String str = orderService.printOrderMsgTwo();
// 模拟线程任务执行
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("异步执行结果: " + str);
System.out.println(Thread.currentThread().getName()
+ " 线程结束执行任务...");
return "success";
}
}
方法执行结果:
http-nio-8081-exec-1 线程开始执行任务...
输出printOrderMsgOne方法信息:
http-nio-8081-exec-1 输出message one...
输出printOrderMsgTwo方法信息:
异步执行结果: null
http-nio-8081-exec-1 线程结束执行任务...
task-1 输出message two...
在orderOne方法中获取不到printOrderMsgTwo方法异步执行的结果,无论printOrderMsgTwo方法在orderOne方法响应之前完成还是之后完成,都获取不到printOrderMsgTwo方法的异步执行结果;
1.3 方法返回值类型是Future
java
@Configuration
@EnableAsync
public class CommonConfig {
}
@Service
public class OrderService {
public void printOrderMsgOne() {
try {
// 模拟线程任务执行
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("\t" + Thread.currentThread().getName()
+ " 输出message one...");
}
@Async
public Future<String> printOrderMsgTwo() {
try {
// 模拟线程任务执行
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("\t" + Thread.currentThread().getName()
+ " 输出message two...");
return new AsyncResult<>("printOrderMsgTwo successfully");
}
}
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private OrderService orderService;
@GetMapping("/one")
public String orderOne() {
System.out.println(Thread.currentThread().getName()
+ " 线程开始执行任务...");
System.out.println("输出printOrderMsgOne方法信息: ");
orderService.printOrderMsgOne();
System.out.println("输出printOrderMsgTwo方法信息: ");
Future<String> future = orderService.printOrderMsgTwo();
// 模拟线程任务执行
try {
Thread.sleep(3000);
String str = future.get();
System.out.println("异步执行结果: " + str);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ " 线程结束执行任务...");
return "success";
}
}
方法执行结果:
http-nio-8081-exec-2 线程开始执行任务...
输出printOrderMsgOne方法信息:
http-nio-8081-exec-2 输出message one...
输出printOrderMsgTwo方法信息:
task-2 输出message two...
异步执行结果: printOrderMsgTwo successfully
http-nio-8081-exec-2 线程结束执行任务...
orderOne方法在http-nio-8081-exec-2线程中执行,printOrderMsgTwo在task-2线程中执行;
printOrderMsgTwo的方法返回值类型是Future,Future中的get方法是阻塞方法,所以orderOne方法会一直阻塞直到获得异步执行结果才会响应;
二 自定义线程池
@Async注解的value属性用来指定使用具体的线程池
java
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Async {
String value() default "";
}
java
@Configuration
@EnableAsync
public class CommonConfig {
@Bean("threadPoolOne")
public ThreadPoolTaskExecutor threadPool() {
ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor();
threadPool.setCorePoolSize(10);
threadPool.setMaxPoolSize(15);
threadPool.setQueueCapacity(15);
threadPool.setKeepAliveSeconds(60);
return threadPool;
}
@Bean("threadPoolTwo")
public ThreadPoolTaskExecutor threadPoolTwo() {
ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor();
threadPool.setCorePoolSize(10);
threadPool.setMaxPoolSize(15);
threadPool.setQueueCapacity(15);
threadPool.setKeepAliveSeconds(60);
return threadPool;
}
}
@Service
public class OrderService {
public void printOrderMsgOne() {
try {
// 模拟线程任务执行
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("\t" + Thread.currentThread().getName()
+ " 输出message one...");
}
@Async("threadPoolTwo")
public CompletableFuture<String> printOrderMsgTwo() {
try {
// 模拟线程任务执行
Thread.sleep(10000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("\t" + Thread.currentThread().getName()
+ " 输出message two...");
return CompletableFuture.completedFuture("printOrderMsgTwo successfully");
}
}
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private OrderService orderService;
@GetMapping("/one")
public String orderOne() {
System.out.println(Thread.currentThread().getName()
+ " 线程开始执行任务...");
System.out.println("输出printOrderMsgOne方法信息: ");
orderService.printOrderMsgOne();
System.out.println("输出printOrderMsgTwo方法信息: ");
CompletableFuture<String> future = orderService.printOrderMsgTwo();
// 模拟线程任务执行
try {
Thread.sleep(3000);
String str = future.get();
System.out.println("异步执行结果: " + str);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ " 线程结束执行任务...");
return "success";
}
}
方法执行结果:
http-nio-8081-exec-1 线程开始执行任务...
输出printOrderMsgOne方法信息:
http-nio-8081-exec-1 输出message one...
输出printOrderMsgTwo方法信息:
threadPoolTwo-1 输出message two...
异步执行结果: printOrderMsgTwo successfully
http-nio-8081-exec-1 线程结束执行任务...
orderOne方法用的是http-nio-8081-exec-1线程,printOrderMsgTwo方法用的threadPoolTwo线程池里面的线程;