В основном такое поведение исходит из реализации ScheduledExecutorService
, которая используется внутри Spring. Если вы запустите этот код, вы заметите такое же поведение:
public static void main(String[] args) throws Exception {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(10);
executor.schedule(() -> {
System.out.println("Running task in thread " + Thread.currentThread().getId());
try {
Thread.sleep(Integer.MAX_VALUE);
} catch (InterruptedException e) {
System.out.println("interrupted while sleeping");
}
}, 1000, TimeUnit.MILLISECONDS);
Thread.sleep(10000);
executor.shutdownNow();
}
Когда вы отправляете задачу в запланированный пул потоков, она упаковывается с помощью RunnableScheduledFuture
, который передается методу delayedExecute
. Этот метод добавляет задачу в очередь задач и запускает новый воркер, если текущее количество воркеров меньше corePoolSize
. Worker пытается получить задачу из очереди и обработать ее, вызывая метод run
. Существует специальная реализация DelayedWorkQueue
, которая возвращает задачи, только если они готовы к выполнению. Вот как выглядит run
метод RunnableScheduledFuture
:
/**
* Overrides FutureTask version so as to reset/requeue if periodic.
*/
public void run() {
boolean periodic = isPeriodic();
if (!canRunInCurrentRunState(periodic))
cancel(false);
else if (!periodic)
ScheduledFutureTask.super.run();
else if (ScheduledFutureTask.super.runAndReset()) {
setNextRunTime();
reExecutePeriodic(outerTask);
}
}
Как видите, он вызывает реальную логику задачи в runAndReset
, вычисляет время следующего выполнения и снова отправляет ту же обновленную задачу в очередь (reExecutePeriodic
почти совпадает с schedule
). Существует только одна периодическая задача для всех выполнений, которая повторно отправляется снова и снова с обновленным временем после завершения предыдущего выполнения. Таким образом, такой пул потоков запускает только один экземпляр каждого типа задач в любой момент и масштабируется только для разных типов задач.
Если вам интересно, как Spring планирует задачи, взгляните на класс ScheduledTaskRegistrar
и, в частности, на метод scheduleFixedDelayTask
.
person
Nikita Gorbachevski
schedule
20.12.2017