Java-таймер проти ExecutorService?


263

У мене є код, в якому я планую завдання, використовуючи java.util.Timer. Я озирався і бачив, як ExecutorServiceможна зробити те саме. Отже, це питання тут, ви використовували Timerта ExecutorServiceпланували завдання, яка користь від використання іншого над іншим?

Також хотів перевірити, чи хтось користувався Timerкласом і натрапив на якісь проблеми, які ExecutorServiceвирішив для них.


1
А якщо вам потрібно щось ще більш функціональне, ознайомтеся з кварцом . Це дає вам набагато більше контролю за роботою, включаючи плановий графік, кластерне планування, індивідуальний контроль над робочими місцями (такі поняття, як один запуск, залежність тощо). --Tim
Тім

Відповіді:


313

Відповідно до Java Concurrency in Practice :

  • Timerможе бути чутливим до змін у системному годиннику, ScheduledThreadPoolExecutorчи не так.
  • Timerмає лише один потік виконання, тому тривале завдання може затримувати інші завдання. ScheduledThreadPoolExecutorможна налаштувати з будь-якою кількістю потоків. Крім того, ви маєте повний контроль над створеними нитками, якщо хочете (надавши ThreadFactory).
  • Винятки під час виконання, що TimerTaskвбиваються, знищують цю нитку, роблячи таким чином Timerмертвим :-( ... тобто заплановані завдання більше не виконуватимуться. ScheduledThreadExecutorНе тільки виловлює винятки з виконання, але й дозволяє вам обробляти їх, якщо хочете (переосмисливши afterExecuteметод від ThreadPoolExecutor). викинутий виняток буде скасовано, але інші завдання продовжуватимуться виконуватись.

Якщо ви можете використовувати ScheduledThreadExecutorзамість цього Timer, зробіть це.

Ще одне ... хоча ScheduledThreadExecutorв бібліотеці Java 1.4 недоступна, є Backport від JSR 166 ( java.util.concurrent) до Java 1.2, 1.3, 1.4 , який має ScheduledThreadExecutorклас.


63

Якщо вам це доступно, важко придумати причину не використовувати рамку виконавця Java 5. Дзвінки:

ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();

дасть вам ScheduledExecutorServiceфункціонал, схожий на Timer(тобто це буде однопоточний), але доступ до якого може бути дещо масштабнішим (під кришкою він використовує паралельні структури, а не повну синхронізацію, як з Timerкласом). Використання ScheduledExecutorServiceтакож дає вам такі переваги, як:

  • Ви можете налаштувати його за потреби (див. newScheduledThreadPoolExecutor()Або ScheduledThreadPoolExecutorклас)
  • Екзекуційні виконання можуть повернути результати

Про єдині причини, на які Timerя можу придуматись:

  • Він доступний до Java 5
  • Подібний клас передбачений в J2ME, який може полегшити перенесення вашої програми (але в цьому випадку не було б дуже складно додати загальний шар абстракції)

1
Іншою причиною використання TimerTaskможе бути наявність scheduledExecutionTime()методу, який, схоже, не має еквівалента в ScheduledExecutorService.
Рохіт Агарвал

3
Ще одна примітка: я пишу цей коментар у 2k17, більше немає J2ME. вона вже мертва.
msangel

1
Java-таймер-клас - хитрий.
JohnyTex

26

ExecutorService є новішим та загальнішим. Таймер - це лише потік, який періодично виконує заплановані для нього речі.

ExecutorService може бути пулом потоків, або навіть розповсюджуватися по інших системах у кластері та виконувати такі дії, як одноразове виконання пакету тощо.

Подивіться, що кожен пропонує вирішити.



8

З сторінки документації Oracle на ScheduledThreadPoolExecutor

ThreadPoolExecutor , який додатково може запланувати команди для запуску після заданої затримки, або періодично виконувати. Цей клас є кращим для Таймера, коли потрібно декілька робочих потоків або коли потрібна додаткова гнучкість або можливості ThreadPoolExecutor (на який розширюється цей клас).

ExecutorService/ThreadPoolExecutorабо ScheduledThreadPoolExecutorце очевидний вибір, коли у вас є кілька робочих ниток.

Плюси ExecutorServiceпонадTimer

  1. Timerне може скористатися наявними процесорними ядрами, на відміну від ExecutorServiceособливо завдань, що використовують аромати ExecutorServiceтипу ForkJoinPool
  2. ExecutorServiceнадає API спільної роботи, якщо вам потрібна координація між декількома завданнями. Припустимо, що вам належить подати N кількість робочих завдань і дочекатися їх виконання. Ви можете легко досягти цього за допомогою API invokeAll . Якщо ви хочете досягти того ж за допомогою декількох Timerзавдань, це було б не просто.
  3. ThreadPoolExecutor забезпечує кращу API для управління життєвим циклом теми.

    Пули ниток вирішують дві різні проблеми: вони зазвичай забезпечують покращену ефективність при виконанні великої кількості асинхронних завдань за рахунок скорочення накладних викликів на виконання завдань, і вони забезпечують засіб обмеження та управління ресурсами, включаючи потоки, споживаними при виконанні колекції завдання. Кожен ThreadPoolExecutor також підтримує основні статистичні дані, наприклад, кількість виконаних завдань

    Трохи переваг:

    а. Ви можете створити / керувати / контролювати життєвий цикл ниток та оптимізувати накладні витрати на створення ниток

    б. Ви можете контролювати обробку завдань (Work Stealing, ForkJoinPool, invokeAll) тощо.

    c. Ви можете стежити за ходом та здоров’ям ниток

    г. Забезпечує кращий механізм обробки винятків


5

Моя причина іноді віддаю перевагу таймеру над Executors.newSingleThreadScheduledExecutor () - це те, що я отримую набагато чистіший код, коли мені потрібен таймер для виконання на демонових потоках.

порівняти

private final ThreadFactory threadFactory = new ThreadFactory() {
    public Thread newThread(Runnable r) {
        Thread t = new Thread(r);
        t.setDaemon(true);
        return t;
    }
};
private final ScheduledExecutorService timer = Executors.newSingleThreadScheduledExecutor(threadFactory); 

з

private final Timer timer = new Timer(true);

Я роблю це, коли мені не потрібна надійність служби виконавця.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.