目录
使用异步注解创建异步任务
@Async注解
使用Demo
线程池配置
Spring Boot默认用于异步任务线程池配置
线程池配置
线程池隔离
为什么需要线程池隔离?
线程池隔离实现Demo
线程池配置:
异步任务:
测试demo
参考内容:
使用异步注解创建异步任务
@Async注解
异步注解,需要在 springboot主程序上配置@EnableAsync。
使用条件:任务本身之间不存在依赖关系
使用Demo
@Component
@Slf4j
public class AsyncTasksService {
public static Random random = new Random();
@Async
public CompletableFuture<String> doTaskOne() throws Exception {
log.info("doTaskOne()开始");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("doTaskOne()执行结束,耗时:" + (end - start) + "毫秒");
return CompletableFuture.completedFuture("doTaskOne()执行结束");
}
@Async
public CompletableFuture<String> doTaskTwo() throws Exception {
log.info("doTaskTwo()开始");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("doTaskTwo()执行结束,耗时:" + (end - start) + "毫秒");
return CompletableFuture.completedFuture("doTaskTwo()执行结束");
}
@Async
public CompletableFuture<String> doTaskThree() throws Exception {
log.info("doTaskThree()开始");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("doTaskThree()执行结束,耗时:" + (end - start) + "毫秒");
return CompletableFuture.completedFuture("doTaskThree()执行结束");
}
}
@SpringBootTest
@Slf4j
@RunWith(SpringRunner.class)
public class AsyncTasksTest {
@Resource
private AsyncTasksService asyncTasksService;
@Test
public void test() throws Exception {
long start = System.currentTimeMillis();
CompletableFuture<String> task1 = asyncTasksService.doTaskOne();
CompletableFuture<String> task2 = asyncTasksService.doTaskTwo();
CompletableFuture<String> task3 = asyncTasksService.doTaskThree();
CompletableFuture.allOf(task1, task2, task3).join();
long end = System.currentTimeMillis();
log.info("任务全部完成,总耗时:" + (end - start) + "毫秒");
}
}
测试结果:
11:02:20.078 [task-3] INFO com.springwork.high.asyncTasks.AsyncTasksService - doTaskThree()开始
11:02:20.078 [task-1] INFO com.springwork.high.asyncTasks.AsyncTasksService - doTaskOne()开始
11:02:20.078 [task-2] INFO com.springwork.high.asyncTasks.AsyncTasksService - doTaskTwo()开始
11:02:24.453 [task-2] INFO com.springwork.high.asyncTasks.AsyncTasksService - doTaskTwo()执行结束,耗时:4375毫秒
11:02:26.571 [task-1] INFO com.springwork.high.asyncTasks.AsyncTasksService - doTaskOne()执行结束,耗时:6493毫秒
11:02:27.570 [task-3] INFO com.springwork.high.asyncTasks.AsyncTasksService - doTaskThree()执行结束,耗时:7492毫秒
11:02:27.571 [main] INFO com.springwork.high.AsyncTasksTest - 任务全部完成,总耗时:7500毫秒
线程池配置
为了控制异步任务的并发不影响到应用的正常运作,我们必须要对线程池做好相应的配置,防止资源的过渡使用
Spring Boot默认用于异步任务线程池配置
源码位置:org.springframework.boot.autoconfigure.task.TaskExecutionProperties
线程池配置
spring:
task:
execution:
pool:
core-size: 8
max-size: 5
queue-capacity: 10
keep-alive: 60s
allow-core-thread-timeout: true
shutdown:
await-termination: false
await-termination-period:
thread-name-prefix: hightask-
task: execution: pool: core-size: 8 (线程池创建时的初始化线程数,默认为8) max-size: 5 (线程池的最大线程数,默认为int最大值,即(2^31)-1) queue-capacity: 10 (用来缓冲执行任务的队列,默认为int最大值,即(2^31)-1) keep-alive: 60s (线程终止前允许保持空闲的时间) allow-core-thread-timeout: true (是否允许核心线程超时) shutdown: await-termination: false (是否等待剩余任务完成后才关闭应用) await-termination-period: (等待剩余任务完成的最大时间) thread-name-prefix: hightask- (线程名的前缀)
配置线程池,并将初始化线程数改成2后结果:
15:11:00.786 [hightask-1] INFO com.springwork.high.asyncTasks.AsyncTasksService - doTaskOne()开始
15:11:00.786 [hightask-2] INFO com.springwork.high.asyncTasks.AsyncTasksService - doTaskTwo()开始
15:11:02.434 [hightask-2] INFO com.springwork.high.asyncTasks.AsyncTasksService - doTaskTwo()执行结束,耗时:1648毫秒
15:11:02.434 [hightask-2] INFO com.springwork.high.asyncTasks.AsyncTasksService - doTaskThree()开始
15:11:04.397 [hightask-2] INFO com.springwork.high.asyncTasks.AsyncTasksService - doTaskThree()执行结束,耗时:1963毫秒
15:11:04.757 [hightask-1] INFO com.springwork.high.asyncTasks.AsyncTasksService - doTaskOne()执行结束,耗时:3971毫秒
15:11:04.757 [main] INFO com.springwork.high.AsyncTasksTest - 任务全部完成,总耗时:3979毫秒
线程池隔离
为什么需要线程池隔离?
@Async
创建的异步任务都是共用的一个线程池,当有一些异步任务碰到性能问题的时候,是会直接影响其他异步任务的。
线程池隔离实现Demo
线程池配置:
package com.springwork.high.asyncTasks;
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.Executor;
import java.util.concurrent.ThreadPoolExecutor;
/**
* @author gj
* @version 1.0.0
* @date 2023/5/26 15:25
*/
@EnableAsync
@Configuration
public class AsyncTasksPoolConfig {
@Bean(name = "highExecutor1")
public Executor asyncTaskExecutor1() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(10);
executor.setKeepAliveSeconds(60);
executor.setThreadNamePrefix("high-1-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
@Bean(name = "highExecutor2")
public Executor asyncTaskExecutor2() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(2);
executor.setQueueCapacity(10);
executor.setKeepAliveSeconds(60);
executor.setThreadNamePrefix("high-2-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
}
异步任务:
package com.springwork.high.asyncTasks;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
/**
* @author gj
* @version 1.0.0
* @date 2023/5/26 10:17
*/
@Component
@Slf4j
public class AsyncTasksService {
public static Random random = new Random();
@Async("highExecutor1")
public CompletableFuture<String> doTaskOne(String taskName) throws Exception {
log.info("开始任务:"+taskName);
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("执行结束"+taskName+"耗时:" + (end - start) + "毫秒");
return CompletableFuture.completedFuture("doTaskOne()执行结束");
}
@Async("highExecutor2")
public CompletableFuture<String> doTaskTwo(String taskName) throws Exception {
log.info("开始任务:"+taskName);
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("执行结束"+taskName+"耗时:" + (end - start) + "毫秒");
return CompletableFuture.completedFuture("执行结束");
}
}
测试demo
CompletableFuture<String> task1 = asyncTasksService.doTaskOne("1");
CompletableFuture<String> task2 = asyncTasksService.doTaskOne("2");
CompletableFuture<String> task3 = asyncTasksService.doTaskOne("3");
CompletableFuture<String> task4 = asyncTasksService.doTaskTwo("4");
CompletableFuture<String> task5 = asyncTasksService.doTaskTwo("5");
CompletableFuture<String> task6 = asyncTasksService.doTaskTwo("6");
CompletableFuture.allOf(task1, task2, task3,task4,task5,task6).join();
测试结果:
15:44:50.899 [high-1-1] INFO com.springwork.high.asyncTasks.AsyncTasksService - 开始任务:1
15:44:50.899 [high-2-2] INFO com.springwork.high.asyncTasks.AsyncTasksService - 开始任务:5
15:44:50.899 [high-1-2] INFO com.springwork.high.asyncTasks.AsyncTasksService - 开始任务:2
15:44:50.899 [high-2-1] INFO com.springwork.high.asyncTasks.AsyncTasksService - 开始任务:4
15:44:51.159 [high-1-2] INFO com.springwork.high.asyncTasks.AsyncTasksService - 执行结束2耗时:260毫秒
15:44:51.159 [high-1-2] INFO com.springwork.high.asyncTasks.AsyncTasksService - 开始任务:3
15:44:51.442 [high-1-1] INFO com.springwork.high.asyncTasks.AsyncTasksService - 执行结束1耗时:542毫秒
15:44:52.724 [high-1-2] INFO com.springwork.high.asyncTasks.AsyncTasksService - 执行结束3耗时:1564毫秒
15:45:00.414 [high-2-2] INFO com.springwork.high.asyncTasks.AsyncTasksService - 执行结束5耗时:9515毫秒
15:45:00.414 [high-2-2] INFO com.springwork.high.asyncTasks.AsyncTasksService - 开始任务:6
15:45:00.690 [high-2-1] INFO com.springwork.high.asyncTasks.AsyncTasksService - 执行结束4耗时:9791毫秒
15:45:00.764 [pool-2-thread-1] INFO com.springwork.high.common.ScheduleTaskCommon - CurrentTime: 2023-05-26T15:45:00.764
15:45:08.855 [high-2-2] INFO com.springwork.high.asyncTasks.AsyncTasksService - 执行结束6耗时:8440毫秒
15:45:08.856 [main] INFO com.springwork.high.AsyncTasksTest - 任务全部完成,总耗时:17964毫秒
参考内容:
http://t.csdn.cn/Drzb4
http://t.csdn.cn/9usjv