java - 使用 Spring ScheduledTaskRegistrar 进行异步调度

标签 java spring spring-scheduled

我有问题,我想在运行时创建计划任务。计划任务应以固定速率触发。但现在我遇到的问题是手动设置计划没有以异步方式触发。

主要问题是,我们没有任何可以启动调度程序的修复点。当我读取特定值 (1) 时,它应该被创建,当值变回 (0) 时,它应该被销毁。否则,我们可以使用下面测试 1 中描述的注释配置。

到目前为止我已经尝试过:

<强>1。使用 @Scheduled(fixedRate = 500L)@Async

进行安排

代码

@Async
@Scheduled(fixedRate = 500L)
public void annotationTest() {
    UUID id = UUID.randomUUID();
    log.warn("Hello from Thread {} going to sleep", id);
    try {
        Thread.sleep(1000L);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    log.warn("Finished Thread {}", id);
}

还在类级别具有 @EnableAsync@EnableScheduling 注释。

结果

09:56:24.855 [task-5] : Hello from Thread 3b5514b2-3b80-4641-bf12-2cd320c4b6e5 going to sleep
09:56:25.355 [task-6] : Hello from Thread e98514a7-e193-422b-9569-f7635deb33f8 going to sleep
09:56:25.356 [task-4] : Finished Thread d86f5f24-bffb-4ddd-93fe-2334ed48cf91
09:56:25.854 [task-7] : Hello from Thread cfc2ab03-4e7e-4a4a-aa08-41d696cb6df7 going to sleep
09:56:25.855 [task-5] : Finished Thread 3b5514b2-3b80-4641-bf12-2cd320c4b6e5
09:56:26.355 [task-6] : Finished Thread e98514a7-e193-422b-9569-f7635deb33f8

评论

这按预期工作,但我们无法使用它,因为我们必须在运行时创建调度程序并在特定时间/输入后销毁它。

<强>2。设置 ScheduledTaskRegistrar

代码

//@Configuration

@Bean
public ScheduledTaskRegistrar scheduledTaskRegistrar() {
    ScheduledTaskRegistrar scheduledTaskRegistrar = new ScheduledTaskRegistrar();
    scheduledTaskRegistrar.setScheduler(threadPoolTaskScheduler());
    return scheduledTaskRegistrar;
}

@Bean
public TaskScheduler threadPoolTaskScheduler() {
    ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
    scheduler.setPoolSize(20);
    return scheduler;
}

//@Component

public void printMessages() {
    scheduledTaskRegistrar.scheduleFixedRateTask(new FixedRateTask(new OwnRunnable(), 500L, 0L));
}

OwnRunnable 也会 hibernate 1 秒,然后打印完成文本

结果

10:13:56.983 [TaskScheduler-1] : Finished Thread 73f70de9-35d9-47f0-801b-fb2857ab1c34
10:13:56.984 [TaskScheduler-3] : Hello from Thread 7ab16380-8dba-49e1-bf0d-de8235f81195 going to sleep
10:13:57.984 [TaskScheduler-3] : Finished Thread 7ab16380-8dba-49e1-bf0d-de8235f81195
10:13:57.984 [TaskScheduler-2] : Hello from Thread cc152d2e-f93b-4770-ac55-853a4dd6be97 going to sleep
10:13:58.985 [TaskScheduler-2] : Finished Thread cc152d2e-f93b-4770-ac55-853a4dd6be97
10:13:58.985 [TaskScheduler-4] : Hello from Thread 8d4510a4-773d-49f3-b51b-e58e425b0b68 going to sleep

评论

我们可以看到任务以同步方式运行,不符合我们的要求。

<强>3。其他测试

所有其他测试与 2 中描述的测试类似,但将使用 ScheduledTaskRegistrar 的一些其他配置。结果与测试2相同。

  • ConcurrentTaskScheduler 而不是 ThreadPoolTask​​Scheduler
  • ConcurrentTaskSchedulerSimpleAsyncTaskExecutor 作为 ConcurrentExecutor
  • ConcurrentTaskSchedulerThreadPoolTask​​Executor 作为 ConcurrentExecutor

问题

如何使用测试 2 中描述的配置但获得测试 1 的结果?有没有办法将 @Async 注释与测试 2 中描述的解决方案一起使用?或者有人对我的问题有更好/另一种解决方案吗?

最佳答案

是的,这是可能的。假设实现 SchedulingConfigurer 的类有一个方法 doMyJob()。您可以使用 Async 注释该方法并使用 FixRateTask 中的引用。另请注意类级别注释

@Configuration
@EnableAsync
public class MyJobConfig implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.scheduleFixedRateTask(new FixedRateTask(this::doMyJob, 500L, 0L));
    }

    @Async
    public void doMyJob() {
        try {
            Thread.sleep(1000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

希望对你有帮助

编辑

我提供了未经测试的代码。最近,当我尝试重新创建此场景时,我注意到如果 doMyJobSchedulingConfigurer 内,它不会是真正的异步(如果延迟为 5 秒,作业需要 10 秒,则下一个作业仅在 10 秒后运行)。但将该方法移至服务类会有所帮助。

关于java - 使用 Spring ScheduledTaskRegistrar 进行异步调度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57553786/

相关文章:

spring-boot - 从休息端点停止调度作业

spring-boot - 如何在计划任务中使用 OAuth2RestTemplate?

java - 将二维int数组按照arr[i]的和从低到高排序

java - 绕其轴旋转三角形

java - Spring Boot 在配置问题中定义 bean

java - QueryDSL 不使用 Postgres 索引

java - 如何立即停止Camel Context?

java - 如何计算 BST 中级别的总和

java - 时间格式中的毫秒和纳秒

java - Spring AuthenticationAuditListener 添加有关目标 URL 的信息