在《SpringBoot整合邮件任务》一文中说过,我们可以通过@Async
注解来实现异步调用。但是如果使用自定义线程池,又该如何来控制异步调用的并发呢?
1.首先在启动类中定义好线程池。
@SpringBootApplication
public class ExecutorApplication {
public static void main(String[] args) {
SpringApplication.run(ExecutorApplication.class, args);
}
@EnableAsync
@Configuration
class ExecutorPoolConfig {
@Bean("executor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(20);
executor.setMaxPoolSize(50);
executor.setQueueCapacity(500);
executor.setKeepAliveSeconds(120);
executor.setThreadNamePrefix("executor");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
}
}
相关参数说明如下:
- 核心线程数(CorePoolSize):线程池创建时候初始化的线程数。
- 最大线程数(MaxPoolSize):线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程。
- 缓冲队列(QueueCapacity):用来缓冲执行任务的队列。
- 允许线程的空闲时间(KeepAliveSeconds):当超过了核心线程出之外的线程在空闲时间到达之后会被销毁。
- 线程池名的前缀(ThreadNamePrefix):设置好了之后可以方便我们定位处理任务所在的线程池。
- 线程池对拒绝任务的处理策略(RejectedExecutionHandler):这里采用了CallerRunsPolicy策略,当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务,如果执行程序已关闭,则会丢弃该任务。
2.在线程池创建完成后,只需在@Async
注解中指定线程池名即可让异步调用的执行任务使用这个线程池中的资源来运行。
@Slf4j
@Component
public class TaskExecutor {
@Async("executor")
public void execute() throws Exception {
log.info("开始执行任务1");
long start = System.currentTimeMillis();
Thread.sleep(2000);
long end = System.currentTimeMillis();
log.info("完成任务1,总共耗时:" + (end - start) + "毫秒");
}
@Async("executor")
public void execute2() throws Exception {
log.info("开始执行任务2");
long start = System.currentTimeMillis();
Thread.sleep(2000);
long end = System.currentTimeMillis();
log.info("完成任务2,总共耗时:" + (end - start) + "毫秒");
}
}
3.最后编写单元测试来测试一下。
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class ApplicationTests {
@Autowired
private TaskExecutor te;
@Test
public void testExecutor() throws Exception {
te.execute();
te.execute2();
Thread.currentThread().join();
}
}
网友评论