Таймер Java против ExecutorService?
У меня есть код, где я планирую задачу, используя java.util.timer
, Я огляделся и увидел ExecutorService
может сделать то же самое. Итак, этот вопрос здесь, вы использовали Таймер и ExecutorService
для планирования задач, в чем преимущество одного использования над другим?
Также хотел проверить, использовал ли кто-нибудь Timer
класс и столкнулся с любыми вопросами, которые ExecutorService
решено для них.
7 ответов
В соответствии с параллелизмом Java на практике:
Timer
может быть чувствительным к изменениям системных часов,ScheduledThreadPoolExecutor
нет.Timer
имеет только один поток выполнения, поэтому долго выполняющаяся задача может задержать выполнение других задач.ScheduledThreadPoolExecutor
можно настроить с любым количеством потоков. Кроме того, вы можете полностью контролировать созданные потоки, если хотите (предоставляяThreadFactory
).- Исключения во время выполнения
TimerTask
убить эту одну нить, таким образом делаяTimer
dead:-( ... т.е. запланированные задачи больше не будут выполняться.ScheduledThreadExecutor
не только перехватывает исключения во время выполнения, но и позволяет вам обрабатывать их, если хотите (переопределяяafterExecute
метод изThreadPoolExecutor
). Задача, вызвавшая исключение, будет отменена, но другие задачи продолжат выполняться.
Если вы можете использовать ScheduledThreadExecutor
вместо Timer
, Сделай так.
Еще одна вещь... пока ScheduledThreadExecutor
недоступна в библиотеке Java 1.4, есть Backport of JSR 166 ( java.util.concurrent
) к Java 1.2, 1.3, 1.4, которая имеет ScheduledThreadExecutor
учебный класс.
Если это доступно для вас, то трудно придумать причину, по которой не следует использовать среду исполнения Java 5. Вызов:
ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor();
даст вам ScheduledExecutorService
с аналогичной функциональностью Timer
(т.е. он будет однопоточным), но чей доступ может быть немного более масштабируемым (под капотом он использует параллельные структуры, а не полную синхронизацию, как с Timer
учебный класс). Используя ScheduledExecutorService
также дает вам такие преимущества, как:
- Вы можете настроить его при необходимости (см.
newScheduledThreadPoolExecutor()
илиScheduledThreadPoolExecutor
учебный класс) - "Одноразовые" казни могут вернуть результаты
О единственных причинах придерживаться Timer
Я могу думать о:
- Это доступно до Java 5
- Подобный класс предусмотрен в J2ME, что может упростить перенос вашего приложения (но в этом случае не составит труда добавить общий уровень абстракции).
ExecutorService является более новым и общим. Таймер - это просто поток, который периодически запускает то, что вы запланировали для него.
ExecutorService может быть пулом потоков или даже распространяться на другие системы в кластере и выполнять такие вещи, как одноразовое пакетное выполнение и т. Д.
Просто посмотрите, что каждый предлагает решить.
Вот еще несколько полезных практик по использованию таймера:
http://tech.puredanger.com/2008/09/22/timer-rules/
В общем, я бы использовал Timer для быстрых и грязных вещей и Executor для более надежного использования.
Со страницы документации Oracle на ScheduledThreadPoolExecutor
ThreadPoolExecutor, который может дополнительно запланировать выполнение команд после заданной задержки или периодическое выполнение. Этот класс предпочтительнее, чем Timer, когда требуется несколько рабочих потоков или когда требуется дополнительная гибкость или возможности ThreadPoolExecutor (который расширяет этот класс).
ExecutorService/ThreadPoolExecutor
или же ScheduledThreadPoolExecutor
Это очевидный выбор, когда у вас есть несколько рабочих потоков.
Плюсы ExecutorService
над Timer
Timer
не может использовать преимущества доступных процессорных ядер в отличиеExecutorService
особенно с несколькими задачами с использованием ароматовExecutorService
как ForkJoinPoolExecutorService
предоставляет совместный API, если вам нужна координация между несколькими задачами. Предположим, что вам нужно отправить N рабочих задач и дождаться завершения всех из них. Вы можете легко достичь этого с помощью invokeAll API. Если вы хотите добиться того же с несколькимиTimer
задачи, это было бы не просто.ThreadPoolExecutor предоставляет лучший API для управления жизненным циклом потока.
Пулы потоков решают две разные проблемы: они обычно обеспечивают повышенную производительность при выполнении большого количества асинхронных задач из-за уменьшения накладных расходов на вызовы для каждой задачи, и они обеспечивают средства ограничения и управления ресурсами, в том числе потоками, используемыми при выполнении коллекции задачи. Каждый ThreadPoolExecutor также поддерживает некоторую базовую статистику, такую как количество выполненных задач
Несколько преимуществ:
а. Вы можете создавать / управлять / контролировать жизненный цикл потоков и оптимизировать накладные расходы на создание потоков
б. Вы можете контролировать обработку заданий ( Work Stealing, ForkJoinPool, invokeAll) и т. Д.
с. Вы можете отслеживать прогресс и здоровье потоков
д. Обеспечивает лучший механизм обработки исключений
Моя причина, по которой я иногда предпочитаю 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.
У меня была проблема с таймером, и я заменил его на ScheduledExecutorService , чтобы исправить это.
Проблема заключалась в том, что таймер зависит от системного времени, и каждый раз, когда я его меняю, это влияет на работу приложения. Поэтому я заменил Timer на ScheduledExecutorService , и теперь он работает нормально.