文章转载自:
@bladestone https://blog.csdn.net/blueheart20/article/details/44648667#commentBox
@灵颖桥人 https://blog.csdn.net/qq_22076345/article/details/82194482
1. 何为异步调用?
在解释异步调用之前,我们先来看同步调用的定义;同步就是整个处理过程顺序执行,当各个过程都执行完毕,并返回结果。 异步调用则是只是发送了调用的指令,调用者无需等待被调用的方法完全执行完毕;而是继续执行下面的流程。
例如, 在某个调用中,需要顺序调用 A, B, C三个过程方法;如他们都是同步调用,则需要将他们都顺序执行完毕之后,方算作过程执行完毕; 如B为一个异步的调用方法,则在执行完A之后,调用B,并不等待B完成,而是执行开始调用C,待C执行完毕之后,就意味着这个过程执行完毕了。
2. 常规的异步调用处理方式
在Java中,一般在处理类似的场景之时,都是基于创建独立的线程去完成相应的异步调用逻辑,通过主线程和不同的线程之间的执行流程,从而在启动独立的线程之后,主线程继续执行而不会产生停滞等待的情况。
3. @Async介绍
在Spring中,基于@Async标注的方法,称之为异步方法;这些方法将在执行的时候,将会在独立的线程中被执行,调用者无需等待它的完成,即可继续其他的操作。
@Async注解使用条件:
- @Async注解一般用在类的方法上,如果用在类上,那么这个类所有的方法都是异步执行的;
- 所使用的@Async注解方法的类对象应该是Spring容器管理的bean对象;
- 调用异步方法类上需要配置上注解@EnableAsync
我们在Spring Boot项目中做一下测试,测试代码如下:
异步方法定义以及实现如下:
package com.qijie.demo.zqjhttpclient.service;
import org.springframework.scheduling.annotation.Async;
import java.util.concurrent.Future;
@Async
public interface TestService {
void test();
}
package com.qijie.demo.zqjhttpclient.service.impl;
import com.qijie.demo.zqjhttpclient.service.TestService;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import java.util.concurrent.Future;
@Service
public class TestServiceImpl implements TestService{
public void test(){
System.out.println("ThreadName:" + Thread.currentThread().getName());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("测试Spring 异步调用!");
}
}
调用异步方法的controller类代码如下:
package com.qijie.demo.zqjhttpclient.controller;
import com.qijie.demo.zqjhttpclient.service.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@RestController
@EnableAsync
@RequestMapping(value = "/test")
public class TestController {
@Autowired
private TestService testService;
@GetMapping(value = "/testAsync")
public void print() {
System.out.println("ThreadName:" + Thread.currentThread().getName());
System.out.println("当前线程开始执行测试函数......");
testService.test();
for (int i = 1; i <= 100; i++) {
System.out.print(i + " ");
if (i % 10 == 0) {
System.out.println();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
System.out.println("当前线程测试函数执行完毕......");
}
}
程序启动后,浏览器访问http://localhost:8080/test/testAsync,后台打印日志如下:
可以看出是有两个线程在执行。如果我们去除TestController上的@EnableAsync或者new 一个TestService对象(该对象没有加载进Spring的容器中),那么TestController中的print()方法都会同步执行,后台打印日志也可以看到只有一个线程在执行。
4. 基于@Async无返回值调用
package com.qijie.demo.zqjhttpclient.service;
import org.springframework.scheduling.annotation.Async;
import java.util.concurrent.Future;
@Async
public interface TestService {
void asyncMethodWithVoidReturnType();//基于@Async无返回值调用
Future<String> asyncMethodWithReturnType();//基于@Async有返回值调用
}
package com.qijie.demo.zqjhttpclient.service.impl;
import com.qijie.demo.zqjhttpclient.service.TestService;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import java.util.concurrent.Future;
@Service
public class TestServiceImpl implements TestService{
public void asyncMethodWithVoidReturnType() {
System.out.println("Execute method asynchronously. "
+ Thread.currentThread().getName());
}
public Future<String> asyncMethodWithReturnType() {
System.out.println("Execute method asynchronously - "
+ Thread.currentThread().getName());
try {
Thread.sleep(5000);
return new AsyncResult<String>("hello world !!!!");
} catch (InterruptedException e) {
//
}
return null;
}
}
package com.qijie.demo.zqjhttpclient.controller;
import com.qijie.demo.zqjhttpclient.service.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@RestController
@EnableAsync
@RequestMapping(value = "/test")
public class TestController {
@Autowired
private TestService testService;
@GetMapping(value = "/testAsyncVoidReturnType")
public void testAsyncAnnotationForMethodsNoReturnType(){
testService.asyncMethodWithVoidReturnType();
}
@GetMapping(value = "/testAsyncWithReturnType")
public void testAsyncAnnotationForMethodsWithReturnType()
throws InterruptedException, ExecutionException {
Future<String> future = testService.asyncMethodWithReturnType();//Future接口接收异步方法的返回值
System.out.println(future.get());//打印返回值
}
}
启动项目,在浏览器http://localhost:8080/test/testAsyncVoidReturnType执行结果:
5.基于@Async返回值的调用
在上面代码中可以发现,返回的数据类型为Future类型,其为一个接口。具体的结果类型为AsyncResult,这个是需要注意的地方。在controller方法中调用有返回值的异步方法。启动项目,在浏览器http://localhost:8080/test/testAsyncWithReturnType执行结果如下: