使用 Spring ScheduledTaskRegistrar 进行异步调度
Async scheduling with Spring ScheduledTaskRegistrar
我遇到了问题,我想在 运行 时间内创建计划任务。计划任务应以固定速率触发。但现在我遇到了手动设置计划未以异步方式触发的问题。
主要问题是,我们没有任何可以启动调度程序的修复点。它应该在我读取特定值 (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);
}
在 class 级别上也有 @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
评论
这按预期工作,但我们无法使用它,因为我们必须在 运行 时间内创建调度程序并在特定的 time/input 后销毁它。
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
与 SimpleAsyncTaskExecutor
作为 ConcurrentExecutor
ConcurrentTaskScheduler
与 ThreadPoolTaskExecutor
作为 ConcurrentExecutor
问题
如何使用测试 2 中描述的配置但得到测试 1 的结果?有没有办法将 @Async
注释与测试 2 中描述的解决方案一起使用?或者有人对我的问题有更好的/其他解决方案吗?
是的,这是可能的。假设实现 SchedulingConfigurer 的 class 有一个方法 doMyJob()。您可以使用 Async 注释该方法并使用 FixedRateTask 中的引用。另请注意 class 级别注释
@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 秒后运行)。但是将方法移至服务 class 有所帮助。
我遇到了问题,我想在 运行 时间内创建计划任务。计划任务应以固定速率触发。但现在我遇到了手动设置计划未以异步方式触发的问题。
主要问题是,我们没有任何可以启动调度程序的修复点。它应该在我读取特定值 (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);
}
在 class 级别上也有 @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
评论
这按预期工作,但我们无法使用它,因为我们必须在 运行 时间内创建调度程序并在特定的 time/input 后销毁它。
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
与SimpleAsyncTaskExecutor
作为ConcurrentExecutor
ConcurrentTaskScheduler
与ThreadPoolTaskExecutor
作为ConcurrentExecutor
问题
如何使用测试 2 中描述的配置但得到测试 1 的结果?有没有办法将 @Async
注释与测试 2 中描述的解决方案一起使用?或者有人对我的问题有更好的/其他解决方案吗?
是的,这是可能的。假设实现 SchedulingConfigurer 的 class 有一个方法 doMyJob()。您可以使用 Async 注释该方法并使用 FixedRateTask 中的引用。另请注意 class 级别注释
@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 秒后运行)。但是将方法移至服务 class 有所帮助。