Spring中实现多线程,其实非常简单,只需要在配置类中添加@EnableAsync
就可以使用多线程。在希望执行的并发方法中使用@Async
就可以定义一个线程任务。通过spring给我们提供的ThreadPoolTaskExecutor
就可以使用线程池。
1. Spring Boot主类中定义一个线程池
定义线程池有两种方法,两种方法效果一样,细节略有区别。
1.1 方式一:实现AsyncConfigurer接口
@EnableAsync
@Configuration
public class CustomAsyncConfigurer1 implements AsyncConfigurer {
private final Logger log = LoggerFactory.getLogger(CustomAsyncConfigurer.class);
@Override
@Bean(name = "taskExecutor")//如果系统只定义此一个线程池可以不加@Bean注解,定义多个线程池必须加@Bean注解。
//@Qualifier("taskExecutor2")
public Executor getAsyncExecutor() {
log.debug("Creating Async Task Executor");
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2); //核心线程数
executor.setMaxPoolSize(5); //最大线程数
executor.setQueueCapacity(3); //队列大小
executor.setKeepAliveSeconds(300); //线程最大空闲时间
executor.setThreadNamePrefix("ics-Executor-"); 指定用于新创建的线程名称的前缀。
executor.setRejectedExecutionHandler(
new ThreadPoolExecutor.CallerRunsPolicy()); // 拒绝策略
executor.initialize();
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler();
}
}
1.2 方式一:直接定义ThreadPoolTaskExecutor 类型的Bean
@EnableAsync
@Configuration
public class CustomAsyncConfigurer2 {
private final Logger log = LoggerFactory.getLogger(CustomAsyncConfigurer1.class);
@Bean(name = "taskExecutor2")//必须有@Bean注解
//@Qualifier("taskExecutor2")
public Executor getAsyncExecutor() {
log.debug("Creating Async Task Executor");
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10); //核心线程数
executor.setMaxPoolSize(20); //最大线程数
executor.setQueueCapacity(1000); //队列大小
executor.setKeepAliveSeconds(300); //线程最大空闲时间
executor.setThreadNamePrefix("ics-Executor-"); 指定用于新创建的线程名称的前缀。
executor.setRejectedExecutionHandler(
new ThreadPoolExecutor.CallerRunsPolicy()); // 拒绝策略
executor.initialize();
return executor;
}
}
2.springboot使用异步注解@Async
@Service
public class AsyncService {
private static final Logger log = LoggerFactory.getLogger(AsyncService.class);
@Autowired
private ApplicationContext applicationContext;
//@Autowired
//@Qualifier("taskExecutor1")
// @Resource(name = "taskExecutor1")
private Executor threadPoolTaskExecutor;
@Async
public void asyncInvokeSimplest() {
//Executor bean = applicationContext.getBean(ThreadPoolTaskExecutor.class);
String[] beanNamesForType = applicationContext.getBeanNamesForType(Executor.class);
try {
log.info("asyncSimplest");
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
3. 调用异步方法
@RestController
@RequestMapping("/async")
public class AsyncController {
@Autowired
private AsyncService asyncService;
@GetMapping
public void test(){
for (int i = 0; i <20 ; i++) {
asyncService.asyncInvokeSimplest();
}
}
}
知识点
1)调用异步方法
@Async
public void asyncInvokeSimplest()
必须通过Spring Bean 调用,不可内部调用。
2)如果 同时定义了 CustomAsyncConfigurer1 和 CustomAsyncConfigurer2
@Async
public void asyncInvokeSimplest() 调用此方法 会使用CustomAsyncConfigurer1(优先使用实现 AsyncConfigurer接口的,原因未知 ) 的线程池
3)如果同时定义了多个线程池,如果想在异步方法中指定线程池,需在定义线程池的方法中加上@Bean("beanname") ,并指明bean 的name,同时@Async(“beananme”)
public void asyncInvokeSimplest() 方法也要指定使用的beanname.
4) 如果想在程序中自动注入线程池,两种实现方式
- 使用Qualifier 注解
@EnableAsync
@Configuration
public class CustomAsyncConfigurer2 {
private final Logger log = LoggerFactory.getLogger(CustomAsyncConfigurer1.class);
@Bean(name = "taskExecutor2")//必须有@Bean注解
@Qualifier("taskExecutor2")
public Executor getAsyncExecutor() {
log.debug("Creating Async Task Executor");
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10); //核心线程数
executor.setMaxPoolSize(20); //最大线程数
executor.setQueueCapacity(1000); //队列大小
executor.setKeepAliveSeconds(300); //线程最大空闲时间
executor.setThreadNamePrefix("ics-Executor-"); 指定用于新创建的线程名称的前缀。
executor.setRejectedExecutionHandler(
new ThreadPoolExecutor.CallerRunsPolicy()); // 拒绝策略
executor.initialize();
return executor;
}
}
@Service
public class AsyncService {
private static final Logger log = LoggerFactory.getLogger(AsyncService.class);
@Autowired
private ApplicationContext applicationContext;
@Autowired
@Qualifier("taskExecutor2")
private Executor threadPoolTaskExecutor;
@Async
public void asyncInvokeSimplest() {
//Executor bean = applicationContext.getBean(ThreadPoolTaskExecutor.class);
String[] beanNamesForType = applicationContext.getBeanNamesForType(Executor.class);
try {
log.info("asyncSimplest");
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
- 使用@Resource注解
@EnableAsync
@Configuration
public class CustomAsyncConfigurer2 {
private final Logger log = LoggerFactory.getLogger(CustomAsyncConfigurer1.class);
@Bean(name = "taskExecutor2")//必须有@Bean注解
public Executor getAsyncExecutor() {
log.debug("Creating Async Task Executor");
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10); //核心线程数
executor.setMaxPoolSize(20); //最大线程数
executor.setQueueCapacity(1000); //队列大小
executor.setKeepAliveSeconds(300); //线程最大空闲时间
executor.setThreadNamePrefix("ics-Executor-"); 指定用于新创建的线程名称的前缀。
executor.setRejectedExecutionHandler(
new ThreadPoolExecutor.CallerRunsPolicy()); // 拒绝策略
executor.initialize();
return executor;
}
}
@Service
public class AsyncService {
private static final Logger log = LoggerFactory.getLogger(AsyncService.class);
@Autowired
private ApplicationContext applicationContext;
@Resource(name = "taskExecutor2")//指定bean 的名称
private Executor threadPoolTaskExecutor;
@Async
public void asyncInvokeSimplest() {
//Executor bean = applicationContext.getBean(ThreadPoolTaskExecutor.class);
String[] beanNamesForType = applicationContext.getBeanNamesForType(Executor.class);
try {
log.info("asyncSimplest");
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}