我有多个带有@Scheduled批注的组件,而且我看到即使一次运行预定运行,Spring一次只能启动一个。
@Scheduled
我的用例如下。我希望每个@Scheduled批注在其自己的线程中运行,但对于每个线程仅运行一次。
给定具有两个调度程序的 伪代码 :
@Scheduled(cron = "0 * * * * *") //run every minute public void methodA() { log.info("Running method A"); executeLongRunningJob("Finished method A"); } @Scheduled(cron = "0 * * * * *") //run every minute public void methodB() { log.info("Running method B"); executeLongRunningJob("Finished method B"); } private void executeLongRunningJob(String msg) { Thread.sleep(70 seconds); System.out.println(msg); }
请注意,该任务花费的时间比计划的调度程序要运行的时间更长。 这很关键。我不希望调度程序在完成运行之前再次启动。
开箱即用地运行此代码将为我提供以下输出:
Running method A Finished method A Running method B Finished method B Running method A Finished method A Running method B Finished method B ... and so on
因此很明显,它在单个线程中运行两个调度程序。
当我@Async使用昂贵的方法时,几乎可以得到正确的行为,除了昂贵的方法在启动新调度程序之前尚未完成。
@Async
Running method A Running method B Running method A Running method B Finished method A Finished method B ... and so on
我想要的是此输出:
Running method A Running method B Finished method A Finished method B Running method A Running method B Finished method A Finished method B ... and so on
我该怎么做?我希望每个Scheduler能够同时运行,但是要等到它完成后才能再次运行。记住,我有两个以上的调度程序在相同的时间运行,有时在不同的时间运行。
没错- 默认情况下,调度程序使用大小为1的线程池,因此将按顺序处理每个任务。您可以通过将TaskSchedulerbean 配置为所需的池大小来实现。考虑以下示例:
TaskScheduler
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.scheduling.TaskScheduler; import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler; import java.util.Date; @SpringBootApplication @EnableScheduling public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Bean public TaskScheduler taskScheduler() { final ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); scheduler.setPoolSize(10); return scheduler; } @Scheduled(fixedDelay = 2 * 1000L, initialDelay = 3 * 1000L) public void scheduled1() throws InterruptedException { System.out.println(new Date() + " " + Thread.currentThread().getName() + ": scheduled1"); Thread.sleep(1000); } @Scheduled(fixedDelay = 3 * 1000L, initialDelay = 3 * 1000L) public void scheduled2() throws InterruptedException { System.out.println(new Date() + " " + Thread.currentThread().getName() + ": scheduled2"); Thread.sleep(1000); } }
它将在单独的线程中运行每个计划的任务,例如:
Tue Jul 18 20:21:50 CEST 2017 taskScheduler-1: scheduled2 Tue Jul 18 20:21:50 CEST 2017 taskScheduler-2: scheduled1 Tue Jul 18 20:21:53 CEST 2017 taskScheduler-1: scheduled1 Tue Jul 18 20:21:54 CEST 2017 taskScheduler-3: scheduled2 Tue Jul 18 20:21:56 CEST 2017 taskScheduler-2: scheduled1 Tue Jul 18 20:21:58 CEST 2017 taskScheduler-4: scheduled2 Tue Jul 18 20:21:59 CEST 2017 taskScheduler-1: scheduled1