前言
ThreadpoolTaskExecutor相对于ThreadpoolExecutor来说,是使用了ThreadPoolExecutor并增强,扩展了更多特性。它是Spring提供的线程池,帮助我们快速创建一个可用的线程池来使用。
@Async是Spring的注解,可以加在类或方法上。通俗的来讲,如果加上了这个注解,那么该类或者该方法在使用时将会进行异步处理,也就是创建一个线程来实现这个类或者方法,实现多线程。
使用
1、配置线程池
package com.czf.connect.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* @author zfChen
* @create 2022/1/13 9:49
*/
@EnableAsync //表示开启多线程
@Configuration
public class ThreadPoolConfig {
/**
* 核心线程数
*/
private static final int CORE_POOL_SIZE = 20;
/**
* 最大线程数
*/
private static final int MAX_POOL_SIZE = 40;
/**
* 队列长度
*/
private static final int QUEUE_CAPACITY = 200;
/**
* 线程池维护线程所允许的空闲时间
*/
private static final int KEEP_ALIVE_SECONDS = 60;
@Bean(name = "threadPoolTaskExecutor") //ThreadPoolTaskExecutor不会自动创建ThreadPoolExecutor,需要手动调initialize才会创建。如果@Bean就不需手动,会自动InitializingBean的afterPropertiesSet来调initialize
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 设置线程池最大线程数
executor.setMaxPoolSize(MAX_POOL_SIZE);
// 线程池活跃的线程数
executor.setCorePoolSize(CORE_POOL_SIZE);
// 设置线程队列最大线程数
executor.setQueueCapacity(QUEUE_CAPACITY);
// 线程池维护线程所允许的空闲时间
executor.setKeepAliveSeconds(KEEP_ALIVE_SECONDS);
executor.setThreadNamePrefix("task-async");//线程前缀名称
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
}
2、需要异步操作的方法或类:
@Slf4j
@Component //将该类注入到容器中
public class AsyncTest {
@Async("threadPoolTaskExecutor") //调用该线程池
public void task() throws InterruptedException {
Thread.sleep(4000);
log.info("task异步处理");
}
}
3、测试类
@Slf4j
@RestController
public class PoolTest {
@Autowired
private AsyncTest asyncTest;
@RequestMapping("/pool")
public void poolTest() throws InterruptedException {
log.info("主线程开始");
asyncTest.task();
log.info("主线程结束");
}
}
4、结果:
可以看出是由不同的线程执行。
注意要点
1、@Async需要在Spring环境下才能启动,使用的是AOP动态代理技术
2、@Async使用的是动态代理来实现异步调用,因此不能够在同一个类中进行调用。方法一定要从另一个类中调用,也就是从类的外部调用,类的内部调用是无效的,有可能因为调用方法的是对象本身而不是代理对象,因为没有经过Spring容器。
3、注解的方法必须是public方法
4、需要在@SpringBootApplication启动类或者@configure注解类上 添加注解@EnableAsync启动多线程注解。
5、@Async就会对标注的方法开启异步多线程调用,注意,这个方法的类一定要交给spring容器来管理。
6、异步方法使用注解@Async的返回值只能为void或者Future。
有返回值的异步处理
上述方法实现的是无返回值的异步操作,接下来实现的是有返回值的异步操作,即返回值为Future。
异步方法
@Async("threadPoolTaskExecutor")
public Future<String> task1() throws InterruptedException {
log.info("异步处理开始");
Thread.sleep(2000);
return new AsyncResult<String>("异步处理");
}
@Async("threadPoolTaskExecutor")
public Future<User2> task2() throws InterruptedException {
log.info("异步处理开始");
User2 user2 = new User2();
user2.setName("zhangsan");
user2.setId(1);
Thread.sleep(2000);
return new AsyncResult<User2>(user2);
}
接口实现
@RequestMapping("/pool1")
public String poolTest1() throws InterruptedException, ExecutionException {
log.info("主线程开始");
Future<String> stringFuture = asyncTest.task1();
log.info("主线程结束");
Thread.sleep(2000);
log.info("{}",stringFuture.get());
return stringFuture.get();
}
@RequestMapping("/pool2")
public User2 poolTest2() throws InterruptedException, ExecutionException {
log.info("主线程开始");
Future<User2> stringFuture = asyncTest.task2();
log.info("主线程结束");
Thread.sleep(2000);
log.info("{}",stringFuture.get());
return stringFuture.get();
}
poolTest1方法:
poolTest2方法: