异步方法调用
异步方法调用或异步方法模式是(多线程)面向对象程序设计中用于异步调用对象的潜在的长期运行
方法的一种设计模式。在说异步方法调用时,我们有必要再来看一下同步方法调用。
同步方法调用在程序继续执行之前需要等待同步方法全部执行完毕返回结果。
同步调用是一种典型的阻塞式调用,无论如何我们只能等代上一个任务完成后,才能继续后面的任务。
而异步方法调用,只需要发送调用任务的指令,调用者无需等待被调用的任务完全执行完成,就
可以继续执行后面的任务。
Java中异步调用的处理方式
在Java中,一般情况下都是通过创建独立的线程去完成异步调用的逻辑,主线程与其他线程执行
不同的流程,从而避免主线程被阻塞。
Spring中的异步调用@Async
在Spring中,基于@Async标注的方法,就被转化为异步方法。这些方法在调用时,会在独立的线程
中执行,调用者无需等待其调用完成,就可以继续向下执行。
配置开启@Async
Java代码开启
@Configuration
@EnableAsync
public class SpringAsyncConfig { ... }
或
@SpringBootApplication
@EnableAsync
public class SpringApplication {
public static void main(String[] args) {
SpringApplication.run(Cs2Application.class, args);
}
}
XML配置开启
<task:executor id="myexecutor" pool-size="5" />
<task:annotation-driven executor="myexecutor"/>
标注方法
@Async标注无返回值的方法
@Async //标注使用
public void asyncMethodWithVoidReturnType() {
System.out.println("Execute Void Return Type Method");
}
@Async标注有返回值的方法
@Async
public Future<String> asyncMethodWithReturnType() {
System.out.println("Execute Has Return Type Method");
try {
Thread.sleep(5000);
return new AsyncResult<String>("Return String");
} catch (InterruptedException e) {
//
}
return null;
}
这里方法的返回类型是Future接口,Future接口是Java线程Future模式的实现,用来进行异步计算。
Future模式可以简单的理解为,调用者将任务提交给Future,Future去执行任务,在执行期间
调用者可以继续执行其他任务,在一段时间后,调用者可以通过Future获取到任务的执行结果。
获取方法返回值:
Future<String> future = asyncService.asyncMethodWithReturnType();
while (true) {
if (future.isDone()) { //判断是否执行完毕
System.out.println("Receive Return Value" + future.get());
break;
}
System.out.println("Continue Waiting");
Thread.sleep(1000);
}
@Async方法中的异常处理
配置AsyncUncaughtExceptionHandler 捕获无返回值方法中的异常
@EnableAsync
@Configuration
@Slf4j
public class AsyncConfig implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(8);
executor.setMaxPoolSize(16);
executor.setQueueCapacity(64);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setThreadNamePrefix("SpringAsyncThread-");
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SpringAsyncExceptionHandler();
}
class SpringAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
@Override
public void handleUncaughtException(Throwable throwable, Method method, Object... obj) {
log.error("Exception in async method - {}", throwable.getMessage());
}
}
}
有返回值的异步方法的异常捕获
对于有返回值的异步方法,返回值应当是AsyncResult类的对象,或者是Future接口的子类,
这样在调用Future的get()方法时,就可以捕获ExcecutionException。
@Async方法中的事务处理
在被@Async标注的方法上同时有@Transactional标注时,由于其基于异步处理操作,在对数据库进行操作时,将无法对
事务管理进行控制。
如果方法内的操作需要添加事务管理,可以将相关操作提取出单独的方法,在该方法上添加@Transactional标注。
注意
AsyncService中包含A(), B(), C()三个异步方法,
若在AsyncService的某一方法中调用A,B,C方法是无法异步执行的。
网友评论