Еще один тип пула потоков — пул запланированных задач. Судя по названию, можно предположить, что мы используем данный тип для планирования запуска той или иной задачи, распределенного во времени.

Этот вид сервиса полезен, когда у нас есть задача запуска той или иной активности с условием истечения некоторого времени или периодичности выполнения задачи.

Для использования мы вызываем Executors.newScheduledThreadPool(1).

О параметрах поговорим чуть позже, сейчас нам важно понимать, что при вызове этого метода нам возвращается объект типа ScheduledExecutorService.

ScheduledExecutorService — это интерфейс, унаследованный от ExecutorService.

В этом интерфейсе появляются следующие методы:

Метод Пояснение
ScheduledFuture<?>
schedule(Runnable command,
                                  long delay, TimeUnit unit);
Создает и выполняет однократное действие, которое выполняется после заданной задержки.
<V> ScheduledFuture<V>
schedule(Callable<V> callable,
                                      long delay, TimeUnit unit);
Создает и выполняет объект ScheduledFuture, который выполняется после заданной задержки.
ScheduledFuture<?>
scheduleAtFixedRate(Runnable command,
                                             long initialDelay,
                                             long period,
                                             TimeUnit unit);
Создает и выполняет периодическое действие, которое выполняется вначале после заданной начальной задержки, а затем с заданным периодом; то есть выполнение начнется после initialDelay, затем initialDelay+period, theninitialDelay + 2 * period и так далее.
ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                long initialDelay,
                                                long delay,
                                                TimeUnit unit);
Создает и выполняет периодическое действие, которое выполняется сначала после данной первоначальной задержки, а затем с заданной задержкой между завершением одного выполнения и началом следующего.

Как мы видим, интерфейс нам предоставляет возможность запуска задач с периодичностью или спустя какое-то время.

Далее о методе newScheduledThreadPool.

Вызвать мы его можем несколькими способами:

newScheduledThreadPool(int corePoolSize)
corePoolSize — количество потоков, которые нужно хранить в пуле, даже если они простаивают.
newScheduledThreadPool(int corePoolSize, ThreadFactory threadFactory)

corePoolSize количество потоков, которые нужно хранить в пуле, даже если они простаивают.

threadFactory — фабрика, используемая при создании новых потоков.

Оба метода создадут пул потоков, который может планировать выполнение команд после заданной задержки или для периодического выполнения.

Давайте рассмотрим работу ScheduledThreadPool на примере.

Например, у нас есть задача проверять почту каждые 5 секунд, при этом эта проверка не должна сказываться на работе основной программы и несет за собой возможное дополнительное потребление ресурсов.

У нас есть класс задачи, который моделирует проверку почты.

public class Task implements Runnable {
   @Override
   public void run() {
       System.out.println("Проверяем почту...");
   }
}

Далее мы создаем пул потоков и задаем расписание для выполнения проверки.

ScheduledExecutorService executorService = Executors.newScheduledThreadPool(2);
executorService.scheduleAtFixedRate(new Task(), 0, 5, TimeUnit.SECONDS);

В выводе мы видим каждые 5 секунд:

Проверяем почту...

В целом, такой пул, как и в примере, мы можем использовать для выполнения “сервисных” периодических задач. Сервисными мы называем те задачи, которые должны быть выполнены вне зависимости от работы основного функционала программы.