异步线程设置优先级
前提: @Async 注解可以实现异步功能,但是如果想让其中一些异步任务先于一些异步任务执行,那么这个注解就实现不了了。
参考大神文章:这篇文章,需要大显神通
解决思路:为ThreadPoolTaskExecutor
使用PriorityBlockingQueue
配置
@Bean("CustomTaskExecutor")
public TaskExecutor threadPoolTaskExecutor(
@Value("${spring.async.core-pool-size}") int corePoolSize,
@Value("${spring.async.max-pool-size}") int maxPoolSize,
@Value("${spring.async.queue-capacity}") int queueCapacity) {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor() {
@Override
protected BlockingQueue<Runnable> createQueue(int queueCapacity) {
return new PriorityBlockingQueue<>(queueCapacity);
}
};
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
//....你需要的其他配置
return executor;
}
这里的配置基本和使用@Async
注解时配置线程池的无异,就是使用了PriorityBlockingQueue
去为在等待队列中的线程设置优先级。
优先级比较
public class FutureCustomTask
extends FutureTask<FutureCustomTask> implements Comparable<FutureCustomTask> {
private JobTask task;
public FutureCustomTask(JobTask task) {
//这里null是因为执行任务不需要任何结果
super(task, null);
this.task = task;
}
@Override
public int compareTo(FutureCustomTask o) {
return task.getJob().getPriority().compareTo(o.task.getJob().getPriority());
}
}
调试和输出结果
String类型任务优先级高,List类型任务优先级低
//先来两个String任务,占满核心线程池 核心线程池大小为2!!!
taskExecutor.execute(new FutureCustomTask(
new JobTask(jobBusiness::doString,
new JobEntity(stringParam, 1L))));
taskExecutor.execute(new FutureCustomTask(
new JobTask(jobBusiness::doString,
new JobEntity(stringParam, 1L))));
//再来任务试试看是否为优先级高的先执行
//这里先放 List 优先级低的任务,如果优先级配置生效,它应该最后执行。
taskExecutor.execute(new FutureCustomTask(
new JobTask(jobBusiness::doList,
new JobEntity(lpParam, 2L))));
taskExecutor.execute(new FutureCustomTask(
new JobTask(jobBusiness::doString,
new JobEntity(stringParam, 1L))));
taskExecutor.execute(new FutureCustomTask(
new JobTask(jobBusiness::doString,
new JobEntity(stringParam, 1L))));
taskExecutor.execute(new FutureCustomTask(
new JobTask(jobBusiness::doString,
new JobEntity(stringParam, 1L))));
taskExecutor.execute(new FutureCustomTask(
new JobTask(jobBusiness::doString,
new JobEntity(stringParam, 1L))));
taskExecutor.execute(new FutureCustomTask(
new JobTask(jobBusiness::doString,
new JobEntity(stringParam, 1L))));
输出结果:可见List任务在最后执行完成
2022-06-14 15:30:41.597 INFO 19590 --- [mTaskExecutor-1] c.k.priority.businessTest.JobBusiness : String 类型任务开始执行,休眠5秒模拟该条任务执行耗时------》
2022-06-14 15:30:41.598 INFO 19590 --- [mTaskExecutor-2] c.k.priority.businessTest.JobBusiness : String 类型任务开始执行,休眠5秒模拟该条任务执行耗时------》
2022-06-14 15:30:46.605 INFO 19590 --- [mTaskExecutor-2] c.k.priority.businessTest.JobBusiness : String 类型任务结束执行。
2022-06-14 15:30:46.605 INFO 19590 --- [mTaskExecutor-1] c.k.priority.businessTest.JobBusiness : String 类型任务结束执行。
2022-06-14 15:30:46.608 INFO 19590 --- [mTaskExecutor-2] c.k.priority.businessTest.JobBusiness : String 类型任务开始执行,休眠5秒模拟该条任务执行耗时------》
2022-06-14 15:30:46.608 INFO 19590 --- [mTaskExecutor-1] c.k.priority.businessTest.JobBusiness : String 类型任务开始执行,休眠5秒模拟该条任务执行耗时------》
2022-06-14 15:30:51.614 INFO 19590 --- [mTaskExecutor-2] c.k.priority.businessTest.JobBusiness : String 类型任务结束执行。
2022-06-14 15:30:51.616 INFO 19590 --- [mTaskExecutor-2] c.k.priority.businessTest.JobBusiness : String 类型任务开始执行,休眠5秒模拟该条任务执行耗时------》
2022-06-14 15:30:51.614 INFO 19590 --- [mTaskExecutor-1] c.k.priority.businessTest.JobBusiness : String 类型任务结束执行。
2022-06-14 15:30:51.616 INFO 19590 --- [mTaskExecutor-1] c.k.priority.businessTest.JobBusiness : String 类型任务开始执行,休眠5秒模拟该条任务执行耗时------》
2022-06-14 15:30:56.621 INFO 19590 --- [mTaskExecutor-1] c.k.priority.businessTest.JobBusiness : String 类型任务结束执行。
2022-06-14 15:30:56.621 INFO 19590 --- [mTaskExecutor-2] c.k.priority.businessTest.JobBusiness : String 类型任务结束执行。
2022-06-14 15:30:56.625 INFO 19590 --- [mTaskExecutor-1] c.k.priority.businessTest.JobBusiness : String 类型任务开始执行,休眠5秒模拟该条任务执行耗时------》
2022-06-14 15:30:56.625 INFO 19590 --- [mTaskExecutor-2] c.k.priority.businessTest.JobBusiness : List 类型任务开始执行,休眠5秒模拟该条任务执行耗时------》
2022-06-14 15:31:01.631 INFO 19590 --- [mTaskExecutor-1] c.k.priority.businessTest.JobBusiness : String 类型任务结束执行。
2022-06-14 15:31:01.631 INFO 19590 --- [mTaskExecutor-2] c.k.priority.businessTest.JobBusiness : List 类型任务结束执行。
完整类
调试用的Controller
@RestController
public class PriorityController {
@Autowired
private TaskExecutor taskExecutor;
@Autowired
private JobBusiness jobBusiness;
@GetMapping("/test")
public String test() {
String stringParam = "String任务----->";
List<Map<String, String>> lpParam = new ArrayList<>();
Map<String, String> map = new HashMap<>();
map.put("1", "张三");
map.put("2", "李四");
lpParam.add(map);
//先来两个String任务,占满核心线程池
taskExecutor.execute(new FutureCustomTask(
new JobTask(jobBusiness::doString,
new JobEntity(stringParam, 1L))));
taskExecutor.execute(new FutureCustomTask(
new JobTask(jobBusiness::doString,
new JobEntity(stringParam, 1L))));
//再来任务试试看是否为优先级高的先执行
taskExecutor.execute(new FutureCustomTask(
new JobTask(jobBusiness::doList,
new JobEntity(lpParam, 2L))));
taskExecutor.execute(new FutureCustomTask(
new JobTask(jobBusiness::doString,
new JobEntity(stringParam, 1L))));
taskExecutor.execute(new FutureCustomTask(
new JobTask(jobBusiness::doString,
new JobEntity(stringParam, 1L))));
taskExecutor.execute(new FutureCustomTask(
new JobTask(jobBusiness::doString,
new JobEntity(stringParam, 1L))));
taskExecutor.execute(new FutureCustomTask(
new JobTask(jobBusiness::doString,
new JobEntity(stringParam, 1L))));
taskExecutor.execute(new FutureCustomTask(
new JobTask(jobBusiness::doString,
new JobEntity(stringParam, 1L))));
return "即时返回,任务正在异步执行。。。。。。";
}
}
配置类
@Configuration
public class TaskConfiguration {
@Bean("CustomTaskExecutor")
public TaskExecutor threadPoolTaskExecutor(
@Value("${spring.async.core-pool-size}") int corePoolSize,
@Value("${spring.async.max-pool-size}") int maxPoolSize,
@Value("${spring.async.queue-capacity}") int queueCapacity) {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor() {
@Override
protected BlockingQueue<Runnable> createQueue(int queueCapacity) {
return new PriorityBlockingQueue<>(queueCapacity);
}
};
executor.setCorePoolSize(corePoolSize);
executor.setMaxPoolSize(maxPoolSize);
executor.setQueueCapacity(queueCapacity);
//....你需要的其他配置
return executor;
}
}
任务类
public class FutureCustomTask
extends FutureTask<FutureCustomTask> implements Comparable<FutureCustomTask> {
private JobTask task;
public FutureCustomTask(JobTask task) {
//这里null是因为执行任务不需要任何结果
super(task, null);
this.task = task;
}
@Override
public int compareTo(FutureCustomTask o) {
return task.getJob().getPriority().compareTo(o.task.getJob().getPriority());
}
}
public class JobEntity<T> {
private T jobInfo;
private Long priority;
public JobEntity(T jobInfo, Long priority) {
this.jobInfo = jobInfo;
this.priority = priority;
}
public T getJobInfo() {
return jobInfo;
}
public void setJobInfo(T jobInfo) {
this.jobInfo = jobInfo;
}
public Long getPriority() {
return priority;
}
public void setPriority(Long priority) {
this.priority = priority;
}
}
public class JobTask implements Runnable {
private Consumer<JobEntity> jobConsumer;
private JobEntity jobEntity;
public JobTask(Consumer<JobEntity> jobConsumer, JobEntity jobEntity) {
this.jobConsumer = jobConsumer;
this.jobEntity = jobEntity;
}
public JobEntity getJob() {
return this.jobEntity;
}
@Override
public void run() {
this.jobConsumer.accept(jobEntity);
}
}
业务方法类
@Component
public class JobBusiness {
private final Logger logger = LoggerFactory.getLogger(getClass());
/**
* String 类型任务
*
* @param: jobEntity
* @return: void
*/
public void doString(JobEntity<String> jobEntity) {
logger.info("String 类型任务开始执行,休眠5秒模拟该条任务执行耗时------》");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.info("String 类型任务结束执行。");
}
/**
* 接受List类型任务
*
* @param: jobEntity
* @return: void
*/
public void doList(JobEntity<List<Map<String, String>>> jobEntity) {
logger.info("List 类型任务开始执行,休眠5秒模拟该条任务执行耗时------》");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
logger.info("List 类型任务结束执行。");
}
}
application.properties
spring.async.core-pool-size=2
spring.async.queue-capacity=3
spring.async.max-pool-size=5