如何使用
对于异步方法调用,从Spring3开始提供了@Async
注解,我们只需要在方法上标注此注解,此方法即可实现异步调用。
当然,我们还需要一个配置类,通过Enable模块驱动注解@EnableAsync
来开启异步功能。
线程池配置类
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* 异步线程池配置
*/
@Slf4j
@Configuration
@EnableAsync//此注解也可以放在启动类
public class AsyncThreadPoolConfig implements AsyncConfigurer {
@Bean(name = "asyncExecutor")
public ThreadPoolTaskExecutor asyncThreadPoolTaskExecutor(){
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
//核心线程数
threadPoolTaskExecutor.setCorePoolSize(20);
//最大线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
threadPoolTaskExecutor.setMaxPoolSize(100);
//缓存队列
threadPoolTaskExecutor.setQueueCapacity(50);
//线程空闲时间,当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
threadPoolTaskExecutor.setKeepAliveSeconds(200);
//异步方法内部线程名称
threadPoolTaskExecutor.setThreadNamePrefix("async-");
/**
* 当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize,如果还有任务到来就会采取任务拒绝策略
* 通常有以下四种策略:
* ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
* ThreadPoolExecutor.DiscardPolicy:也是丢弃任务,但是不抛出异常。
* ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新尝试执行任务(重复此过程)
* ThreadPoolExecutor.CallerRunsPolicy:重试添加当前的任务,自动重复调用 execute() 方法,直到成功
*/
threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
threadPoolTaskExecutor.initialize();
return threadPoolTaskExecutor;
}
/**
* 指定默认线程池,使用@Async注解时,不指定线程池名称,默认使用此线程池
*/
@Override
public Executor getAsyncExecutor() {
return asyncThreadPoolTaskExecutor();
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return ((ex, method, params) -> log.error("线程池执行任务发送时出现异常,执行方法为:{}",method.getName()));
}
}
异步方法调用
错误示范:同步方法methodA
中调用异步方法methodB
@Service
public class UserServiceImpl implements UserService {
public User methodA(User user){
System.out.println("执行task1......");
methodB(user);
return user;
}
@Async
public void methodB(User user) {
System.out.println("异步执行task2......");
}
}
*正确使用:*
@RestController
@RequestMapping("/user")
public class UserController(@RequestBody User user){
@Autowired
private UserService userService;
userService.methodA();
userService.methodB();
}
@Service
public class UserServiceImpl implements UserService {
public User methodA(User user){
System.out.println("执行task1......")
return user;
}
@Async
public void methodB(User user) {
System.out.println("异步执行task2......");
}
}
注意事项
@Async失效的几个原因:
1.注解@Async的方法不是
public
方法;
2.方法不是void
或者Future
;
3.未加@EnableAsync
注解;
4.注解@Async方法使用static
修饰会失效;
5.调用方和使用@Async的方法不能在同一个类中;
6.在@Async的方法上使用@Transactional
是起不到作用的,但在调用其的方法上可以有效的使用。