使用Spring ScheduledTaskRegistrar

时间:2019-08-19 09:20:29

标签: 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也将休眠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而非ThreadPoolTaskScheduler
  • ConcurrentTaskScheduler,其中SimpleAsyncTaskExecutorConcurrentExecutor
  • ConcurrentTaskScheduler,其中ThreadPoolTaskExecutorConcurrentExecutor

问题

如何使用测试2中所述的配置,但获得测试1的结果?有没有一种方法可以将@Async注释与测试2中所述的解决方案一起使用?还是有人对我的问题有更好的/其他解决方案?

1 个答案:

答案 0 :(得分:3)

是的,有可能。假设实现SchedulingConfigurer的类具有方法doMyJob()。您可以使用Async注释该方法,并在FixedRateTask中使用引用。还要注意班级注释

@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();
        }
    }
}

希望有帮助

编辑

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