Cri*_*zar 11 java spring multithreading spring-boot
我的项目中有三个方法用 @Scheduled 注释,其中一个是 cron 表达式,另外两个是固定延迟。注释看起来像:
方法一:
@Scheduled(fixedDelay = 20000)
@Async
protected void checkBrokenEngines() {
Run Code Online (Sandbox Code Playgroud)
方法二:
@Scheduled(fixedRate = 20000)
@Async
public void checkAvailableTasks() throws Exception {
Run Code Online (Sandbox Code Playgroud)
方法三:
@Scheduled(cron = "0 0 2 * * ?")
protected void deleteOldData() {
Run Code Online (Sandbox Code Playgroud)
之前我遇到一个问题,当checkBrokenEngines和checkAvailableTasks方法执行速度很慢时,直到前一个执行结束才进行下一次执行。从 StackOverflow 阅读文档和这里的一些主题,我看到我的项目有一些错误的池大小设置,并且方法没有用async注释。(异步用于下一次执行开始,即使旧的没有结束,因为这不会在我的应用程序中引起任何问题)
现在又出现了一个问题,这是我的问题:
deleteOldData()执行该方法时,其他两个方法都不会运行,直到它完成。看到这个方法阻塞了另外两个的执行,我把这个方法注释为async,之后,即使这个方法需要时间来执行,另外两个总是在规定的时间内被正确调用。为什么?根据我的理解,这不应该发生,因为这些方法是用异步记录的,并且池有足够的空间来执行它们。
PS:deleteOldData()不能异步。它必须在前一次执行完成后立即开始。
编辑 1:
异步执行器配置:
@Override
public AsyncTaskExecutor getAsyncExecutor() {
log.debug("Creating Async Task Executor");
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(50);
executor.setMaxPoolSize(50);
executor.setQueueCapacity(10000);
return new ExceptionHandlingAsyncTaskExecutor(executor);
}
Run Code Online (Sandbox Code Playgroud)
所有 @Scheduled标记的调用都将使用默认的单线程执行器来调度任务(异步或其他方式)。
所有@Async任务都移交给不同的 aysnc 线程池执行程序,以便使用 AOP 拦截器执行。
我认为您的困惑来自于异步方法立即返回这一事实,但是当 deleteOldData 运行时,它是同步运行的,因为只有一个线程,它会阻止任何其他计划任务的执行。
因为您有用于计划任务的默认线程池(单线程),所以它们被一个接一个地调度。
使用 @Async 注释的其他方法即使完成与否也会执行。在某些情况下,我有两种同时执行的方法。但是当 deleteOldData 正在执行时,异步方法会停止运行,直到它完成。这是我不明白的,抱歉:/ –
这与调度不同——这是你的异步执行器发挥作用的地方,它们是并发运行的。
您可以通过以下两种方式之一解决此问题:
您可以spring.task.scheduling.pool.size=10 在应用程序属性中使用来设置任务调度程序的池大小。
或者,使用不同的任务调度程序。继续为@Scheduled任务使用默认调度程序并为异步任务配置如下内容(删除计划注释)
有一项增强功能要求将任务调度程序传递给@Scheduled注释,直到您必须手动调度任务。
为异步调用注册一个新的任务调度程序,并在构建后阶段调度方法。就像是
配置
@Bean("asyncTaskScheduler")
public TaskScheduler asyncTaskScheduler() {
return new ThreadPoolTaskScheduler();
}
Run Code Online (Sandbox Code Playgroud)
服务
@Autowired
private TaskScheduler asyncTaskScheduler;
@PostConstruct
void schedule() {
asyncTaskScheduler.scheduleAtFixedRate(this::checkAvailableTasks, 20000L);
asyncTaskScheduler.scheduleAtFixedDelay(this::checkBrokenEngines, 20000L);
}
@Async
public void checkBrokenEngines() {...}
@Async
public void checkAvailableTasks() throws Exception {...}
Run Code Online (Sandbox Code Playgroud)
计划任务由 处理ThreadPoolTaskScheduler,其默认池大小为 1。只有当它们被注释为 时@Async,执行才会传递到 中AsyncTaskExecutor,它为您配置了一个具有更大池大小的专用执行器。
要ThreadPoolTaskScheduler在@Configuration类中配置:
@Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler(){
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setThreadNamePrefix("ThreadPoolTaskScheduler");
scheduler.setPoolSize(50);
return scheduler ;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6046 次 |
| 最近记录: |