使用 spring @Scheduled 的问题 [英] Problems using spring @Scheduled

查看:54
本文介绍了使用 spring @Scheduled 的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的项目中有三个方法用@Scheduled 注释,其中一个是 cron 表达式,另外两个是固定延迟.注释看起来像:

I have three methods on my project annotated with @Scheduled, being one of them a cron expression and the other two are fixed delay. The annotations look like:

方法一:

@Scheduled(fixedDelay = 20000)
@Async
protected void checkBrokenEngines() {

方法二:

@Scheduled(fixedRate = 20000)
@Async
public void checkAvailableTasks() throws Exception {

方法三:

@Scheduled(cron = "0 0 2 * * ?")
protected void deleteOldData() {

之前我遇到了一个问题,当checkBrokenEnginescheckAvailableTasks 方法执行速度很慢时,下一次执行直到前一次结束才发生.从 StackOverflow 阅读文档和此处的一些主题,我发现我的项目有一些错误的池大小设置,并且这些方法没有使用 async 进行注释.(即使旧的没有结束,异步也用于下一次执行开始,因为这不会在我的应用程序中造成任何问题)

Previously I had a problem that when the checkBrokenEngines and checkAvailableTasks methods were slow to be executed, the next executions did not happen until the previous one ended. Reading the documentation and some topics here from the StackOverflow, I saw that my project had some wrong pool size settings and the methods were not annotated with async. (Async was for the next execution start even if the old one doesn't end, as this does not cause any problems in my application)

现在又出现了一个问题,这是我的问题:

Now another problem has come up, which is my question:

deleteOldData() 方法被执行时,其他两个方法都不会运行,直到它完成.看到这个方法阻塞了另外两个的执行,我把这个方法注释为async,之后,即使这个方法需要时间来执行,另外两个总是在规定的时间内被正确调用.为什么?根据我的理解,这不应该发生,因为这些方法是用异步标记的,并且池有足够的空间来执行它们.

When the deleteOldData() method is executed, neither of the other two methods will run until it finishes. After seeing that this method was blocking the execution of the other two, I annotated the method as async and after that, even if this method takes time to be executed, the other two are always invoked correctly within the stipulated time. Why? In my understanding, this should not happen since those methods are noted with async and the pool has enough space to execute them.

PS:deleteOldData() 不能是异步的.它必须在上一次执行完成后立即开始.

PS: deleteOldData() cannot be async. It must start just after the previous execution has been completed.

编辑 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);
}

推荐答案

All @Scheduled 标记的调用将使用默认的单线程执行器来调度任务(异步或其他方式)).

All @Scheduled marked invocations will use the default single thread executor to schedule tasks (async or otherwise).

所有 @Async 任务都交给不同的 aysnc 线程池执行器,以使用 AOP 拦截器执行.

All @Async tasks are handed off to different aysnc threadpool executor for executions with AOP interceptor.

我认为您的困惑来自于异步方法立即返回这一事实,但是当运行 deleteOldData 时,它是同步运行的,因为只有一个线程,它会阻止任何其他计划任务的执行.

I think your confusion comes from the fact async methods return immediately but when deleteOldData is run, it is running synchronously as there is only one thread, it blocks the execution of any other scheduled tasks.

因为您为计划任务设置了默认线程池(单线程),所以它们被一个接一个地安排.

Because you have default threadpool (single thread) for the scheduled tasks they are scheduled one after the another.

使用@Async 注释的其他方法即使它也执行完成与否.在某些情况下,我有两种执行方法同时.但是当 deleteOldData 执行时,异步方法停止运行直到它完成.这是我不明白的,抱歉:/–

The other methods annotated with @Async they execute even if it finishes or not. In some cases, I have two methods of executing at the same time. But when deleteOldData is executing, the async methods stop to run until it finishes. This what I'm not understanding, sorry :/ –

这与调度不同 - 这是您的异步​​执行器发挥作用并且它们同时运行的地方.

This is different from scheduling - This is where your async executor comes into play and they are run concurrently.

您可以通过以下两种方式之一解决此问题:

You can fix this in one of two ways:

您可以在应用程序属性中使用 spring.task.scheduling.pool.size=10 来设置任务调度程序的池大小.

You can use spring.task.scheduling.pool.size=10 in application properties to set the pool size of task scheduler.

或者,使用不同的任务调度程序.继续为 @Scheduled 任务使用默认调度程序,并为异步任务配置如下内容(删除计划注释)

Alternatively, use different tasks schedulers. Keep using default scheduler for @Scheduled task and configure something like below for async tasks ( remove scheduled annotation )

要求增强将任务调度程序传递给 @Scheduled 注释,直到您必须手动调度任务.

There is an enhancement requested to pass task scheduler to the @Scheduled annotation until then you have to schedule tasks manually.

为异步调用注册一个新的任务调度程序,并在构建后阶段调度方法.类似的东西

Register a new task scheduler for async invocations and schedule the methods in the post construct stage. Something like

配置

@Bean("asyncTaskScheduler")
public TaskScheduler asyncTaskScheduler() {
  return new ThreadPoolTaskScheduler();
}

服务

@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 {...}

这篇关于使用 spring @Scheduled 的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆