异步调用就是不用等待结果的返回就执行后面的逻辑;同步调用则需要等待结果再执行后面的逻辑。
通常我们使用异步操作的时候都会创建一个线程执行一段逻辑,然后把这个线程丢到线程池中去执行
public void asyncDemo(){
ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.execute(() ->{
try {
//业务逻辑
}catch (Exception e){
e.printStackTrace();
}finally {
}
});
}
这种方式尽管使用了Java的Lambda,但看起来没那么优雅。再Spring中有一种更简单的方式来执行异步操作。只需要一个@Async注解即可。
@Async
public void saveLog(){
System.err.println(Thread.currentThread().getName());
}
我们可以直接在Controller中调用这个业务方法,它就是异步执行的,会在默认的线程池中执行。需要注意的是,一定要在外部的类中去调用这个方法,如果在本类中调用则不起作用。最后一定要在启动类上开启异步任务的执行,添加@EnableAsync即可。
@SpringBootApplication
@EnableAsync
public class ServerApplication {
public static void main(String[] args) {
SpringApplication.run(ServerApplication.class, args);
System.out.println("项目启动成功!");
}
}
另外,关于执行异步任务的线程池我们也可以自定义,首先我们定义一个线程池的配置类,用来配置一些参数,代码如下:
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* 线程池的配置类,用来配置一些参数
*/
@Configuration
@ConfigurationProperties(prefix = "spring.task.pool")
@Data
public class TaskThreadPoolConfig {
//核心线程数
private int corePoolSize = 5;
//最大线程数
private int maxPoolSize = 50;
//线程池维护线程所允许的空闲时间
private int keepAliveSeconds = 60;
//队列长度
private int queueCapacity = 10000;
private String threadNamePrefix = "smile-AsyncTask-";
}
然后我们重新定义线程池的配置,代码如下
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.lang.reflect.Method;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 线程池配置
*/
@Configuration
public class AsyncTaskExexutePool implements AsyncConfigurer {
private Logger logger = LoggerFactory.getLogger(AsyncConfigurer.class);
@Autowired
private TaskThreadPoolConfig config;
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(config.getCorePoolSize());
executor.setMaxPoolSize(config.getMaxPoolSize());
executor.setQueueCapacity(config.getQueueCapacity());
executor.setKeepAliveSeconds(config.getKeepAliveSeconds());
executor.setThreadNamePrefix(config.getThreadNamePrefix());
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
//异步任务中异常处理
return new AsyncUncaughtExceptionHandler() {
@Override
public void handleUncaughtException(Throwable throwable, Method method, Object... objects) {
logger.error("==================" +
throwable.getMessage() + "============" + throwable);
logger.error("exception method:" + method.getName());
}
};
}
}
配置完之后我们的异步任务执行的线程池就是我们自定义的了。