使用场景
同步方式:处理过程中,存在多次调用别的服务,当各个过程都执行完毕,返回结果。例如:调用多个接口查询统计数据,最后在组装结果。
异步方式:调用后无须关注调用结果的,例如:图片上传完成后,异步生成缩略图,提升接口性能。
SpringBoot中使用异步执行器步骤
启动类上增加 @EnableAsync
注解
@EnableAsync
@SpringBootApplication
public class AsyncApplication {
public static void main(String[] args) {
SpringApplication.run(AsyncApplication.class, args);
}
}
配置异步执行器
package com.stu.test.async.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurerSupport;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
public class AsyncExecutorConfig extends AsyncConfigurerSupport {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(40);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("asyn-task-ikun-thread-");
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
创建使用异步线程服务类
IKunService
public interface IKunService {
Future<String> futureDanceMethod() throws InterruptedException;
Future<String> futureRapMethod() throws InterruptedException;
}
IKunServiceImpl
,在需要异步执行的方法上增加@Async
package com.stu.test.async.service.impl;
import com.stu.test.async.service.IKunService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service;
import java.util.concurrent.Future;
@Slf4j
@Service
public class IKunServiceImpl implements IKunService {
@Async
@Override
public Future<String> futureDanceMethod() throws InterruptedException {
Thread.sleep(3000);
log.info("Dance 3000");
return new AsyncResult<String>("Dance 3000");
}
@Async
@Override
public Future<String> futureRapMethod() throws InterruptedException {
Thread.sleep(10000);
log.info("Rap 10000");
return new AsyncResult<String>("Rap 10000");
}
}
创建IndexController,用于测试
package com.stu.test.async.controller;
import com.stu.test.async.service.IKunService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
@Slf4j
@RestController
public class IndexController {
@Autowired
private IKunService iKunService;
@GetMapping(value = "/ikun")
public String ikunTest() throws InterruptedException, ExecutionException {
log.info("ikunTest start");
Future danceFuture = iKunService.futureDanceMethod();
Future rapFuture = iKunService.futureRapMethod();
String result = String.format("两年半,%S,%S", danceFuture.get(), rapFuture.get());
log.info("ikunTest result;{}", result);
return result;
}
}
查看执行结果
2023-03-17 15:23:31.598 INFO 19672 --- [nio-8080-exec-4] c.s.t.async.controller.IndexController : ikunTest start
2023-03-17 15:23:34.602 INFO 19672 --- [k-ikun-thread-3] c.s.t.a.service.impl.IKunServiceImpl : Dance 3000
2023-03-17 15:23:41.614 INFO 19672 --- [k-ikun-thread-4] c.s.t.a.service.impl.IKunServiceImpl : Rap 10000
2023-03-17 15:23:41.614 INFO 19672 --- [nio-8080-exec-4] c.s.t.async.controller.IndexController : ikunTest result;两年半DANCE 3000,RAP 10000
可以看出,执行等执行完Dance和Rap之后,最后一起返回了结果。
测试使用版本信息
SpringBoot-2.0.4.RELEASE
其他注意事项
- @Async修饰方法,不能在定义改方法的内部调用,例如
IKunServiceImpl
内部调用futureDanceMethod
、futureRapMethod
都不会异步执行。 - @Async修饰方法需要是
Public
,返回值是void
或者Future