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

Цей вид сервісу стає в нагоді, коли ми маємо запустити певну активність з умовою закінчення певного часу або періодичності виконання такого завдання.

Щоб використати такий сервіс, ми викликаємо 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 секунд:

Перевіряємо пошту...

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