Запуск каждого планировщика 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
на моем дорогом методе я почти получаю правильное поведение, за исключением того, что дорогой метод не завершен до запуска нового планировщика.
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
как я могу это сделать? Я хочу, чтобы каждый планировщик запускался одновременно, но подождите, пока он не будет завершен, прежде чем разрешать запуск снова. Помните, что у меня есть более двух планировщиков, работающих в одно и то же время, а иногда и в разное время.
1 ответов
вы правы - по умолчанию планировщик использует пул потоков с размером 1, поэтому каждая задача обрабатывается последовательно. Вы можете это, настроив TaskScheduler
bean с желаемым размером пула. Рассмотрим следующий пример:
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