Вопрос-ответ

Java Timer vs ExecutorService?

Java Timer vs ExecutorService?

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

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

Переведено автоматически
Ответ 1

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


  • Timer может быть чувствителен к изменениям системных часов, ScheduledThreadPoolExecutor это не так.

  • Timer имеет только один поток выполнения, поэтому длительно выполняемая задача может задерживать другие задачи. ScheduledThreadPoolExecutor может быть настроен с любым количеством потоков. Кроме того, у вас есть полный контроль над созданными потоками, если вы хотите (предоставив ThreadFactory).

  • Исключения во время выполнения, создаваемые в TimerTask убивают этот поток, тем самым делая Timer мертвым :-( ... т. е. Запланированные задачи больше не будут выполняться. ScheduledThreadExecutor не только улавливает исключения во время выполнения, но и позволяет вам обрабатывать их, если вы хотите (переопределяя afterExecute метод из ThreadPoolExecutor). Задача, вызвавшая исключение, будет отменена, но другие задачи продолжат выполняться.

Если вы можете использовать ScheduledThreadExecutor вместо Timer, сделайте это.

И еще кое-что... хотя ScheduledThreadExecutor он недоступен в библиотеке Java 1.4, существует бэкпорт JSR 166 (java.util.concurrent) в Java 1.2, 1.3, 1.4, в котором есть ScheduledThreadExecutor класс.

Ответ 2

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

ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();

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


  • При необходимости вы можете настроить его (см. newScheduledThreadPoolExecutor() или ScheduledThreadPoolExecutor класс)

  • Одноразовые выполнения могут возвращать результаты

Единственные причины придерживатьсяTimer, которые я могу придумать, это:


  • Доступно до Java 5

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

Ответ 3

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

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

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

Ответ 4

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


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


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

Плюсы ExecutorService over Timer


  1. Timer не удается воспользоваться преимуществами доступных ядер процессора, в отличие от ExecutorService особенно при выполнении нескольких задач, использующих варианты, ExecutorService подобные ForkJoinPool

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

  3. ThreadPoolExecutor предоставляет лучший API для управления жизненным циклом потока.



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



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


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


    b. Вы можете управлять обработкой задач (кража работы, ForkJoinPool, invokeAll) и т.д.


    c. Вы можете отслеживать прогресс и работоспособность потоков


    d. Обеспечивает лучший механизм обработки исключений


java