Таймер Java против ExecutorService? - PullRequest
       34

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

248 голосов
/ 04 января 2009

У меня есть код, где я планирую задачу, используя java.util.timer. Я огляделся и увидел, что ExecutorService может сделать то же самое. Итак, этот вопрос здесь, вы использовали Timer и ExecutorService для планирования задач, в чем преимущество одного использования над другим?

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

Ответы [ 6 ]

288 голосов
/ 04 января 2009

Согласно Java-параллелизма на практике :

  • 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 класс.

60 голосов
/ 04 января 2009

Если это доступно для вас, тогда трудно придумать причину , а не , чтобы использовать среду исполнения Java 5 executor. Вызов:

ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();

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

  • При необходимости вы можете настроить его (см. newScheduledThreadPoolExecutor() или ScheduledThreadPoolExecutor класс)
  • Выполнение «один раз» может возвращать результаты

О единственных причинах придерживаться Timer Я могу подумать:

  • Доступно до Java 5
  • Аналогичный класс предоставляется в J2ME, что может упростить перенос вашего приложения (но в этом случае не составит труда добавить общий уровень абстракции)
22 голосов
/ 04 января 2009

ExecutorService является более новым и более общим. Таймер - это просто поток, который периодически запускает то, что вы запланировали для него.

ExecutorService может быть пулом потоков или даже распространяться на другие системы в кластере и выполнять такие вещи, как одноразовое пакетное выполнение и т. Д. *

Просто посмотрите, что каждый предлагает решить.

14 голосов
/ 04 января 2009

Вот еще несколько полезных практик по использованию таймера:

http://tech.puredanger.com/2008/09/22/timer-rules/

В общем, я бы использовал Timer для быстрых и грязных вещей и Executor для более надежного использования.

5 голосов
/ 29 октября 2016

Со страницы документации Oracle на ScheduledThreadPoolExecutor

A ThreadPoolExecutor , который может дополнительно запланировать выполнение команд после заданной задержки или периодическое выполнение. Этот класс предпочтительнее Таймер , когда требуется несколько рабочих потоков или когда требуется дополнительная гибкость или возможности ThreadPoolExecutor (который расширяет этот класс).

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

Плюсы ExecutorService более Timer

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

    Пулы потоков решают две разные проблемы: они обычно обеспечивают повышенную производительность при выполнении большого количества асинхронных задач из-за уменьшения накладных расходов на вызовы для каждой задачи, а также предоставляют средства для ограничения и управления ресурсами, включая потоки, которые используются при выполнении сборник задач. Каждый ThreadPoolExecutor также поддерживает некоторую базовую статистику, такую ​​как количество выполненных задач

    Несколько преимуществ:

    а. Вы можете создавать / управлять / контролировать жизненный цикл потоков и оптимизировать накладные расходы на создание потоков

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

    с. Вы можете следить за ходом и исправностью потоков

    * * +1051 д. Обеспечивает лучший механизм обработки исключений
5 голосов
/ 12 апреля 2015

Причина, по которой я иногда предпочитаю Timer, а не 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);

Я делаю это, когда мне не нужна надежность службы executor.

...