Причина вызова shutdown() для ExecutorService
Я читал об этом довольно много за последние пару часов, и я просто не вижу никакой причины (действительной причины) для вызова shutdown()
на ExecutorService
, если у нас нет огромного приложения, которое хранит, десятки и десятки различных служб executor, которые не используются в течение длительного времени.
Единственное (из того, что я понял), что происходит при завершении работы, - это делать то, что делает нормальный поток, как только он это сделает. Когда обычный поток завершит выполнение метода Runnable (или Callable), он будет передан в сборщик мусора для сбора. С помощью Executor Service потоки будут просто приостановлены, они не будут отмечены для сборки мусора. Для этого необходимо отключение.
Хорошо, вернемся к моему вопросу. Есть ли какая-либо причина вызывать завершение работы на ExecutorService
очень часто или даже сразу после предоставления ему каких-либо задач? Я хотел бы оставить позади случай, когда кто-то делает это, и сразу после этого вызывает awaitTermination()
поскольку это проверено. Как только мы это сделаем, мы должны заново создать новый ExecutorService
, чтобы сделать то же самое. Разве не вся идея для ExecutorService
повторно использовать потоки? Так зачем так быстро уничтожать ExecutorService
?
Разве это не рациональный способ просто создать ExecutorService
(или пару в зависимости от того, сколько вам нужно), затем во время выполнения приложения передайте им задачи, как только они появятся, а затем при выходе из приложения или на некоторых других важных этапах завершите работу. исполнители?
Я хотел бы получить ответ от некоторых опытных программистов, которые пишут много асинхронного кода с использованием ExecutorServices.
Второй вопрос, немного меньше сделок с платформой Android. Если некоторые из вас скажут, что не стоит каждый раз закрывать исполнителей, и вы программируете на Android, не могли бы вы рассказать, как вы справляетесь с этими выключениями (а точнее - когда вы их выполняете), когда мы имеем дело с различными событиями жизненный цикл приложения.
Из-за комментария CommonsWare я сделал пост нейтральным. Я действительно не заинтересован в том, чтобы спорить об этом до смерти, и, кажется, это ведет там. Меня интересует только то, что я спросил у опытных разработчиков, если они хотят поделиться своим опытом. Благодарю.
Ответы
Ответ 1
Метод shutdown()
делает одну вещь: запрещает клиентам отправлять больше работы в службу executor. Это означает, что все существующие задачи будут выполняться до завершения, если не будут предприняты другие действия. Это верно даже для запланированных задач, например, для ScheduledExecutorService: новые экземпляры запланированной задачи не будут запускаться. Это может быть полезно в различных сценариях.
Предположим, у вас есть консольное приложение, в котором есть служба исполнителя, выполняющая N задач. Если пользователь нажимает CTRL-C, вы ожидаете, что приложение завершит работу, возможно, изящно. Что это значит изящно? Возможно, вы хотите, чтобы ваше приложение не могло отправлять больше задач в службу исполнителя, и в то же время вы хотите дождаться завершения ваших существующих N задач. Вы можете добиться этого, используя в качестве крайней меры отключение при отключении:
final ExecutorService service = ... // get it somewhere
Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Performing some shutdown cleanup...");
service.shutdown();
while (true) {
try {
System.out.println("Waiting for the service to terminate...");
if (service.awaitTermination(5, TimeUnit.SECONDS)) {
break;
}
} catch (InterruptedException e) {
}
}
System.out.println("Done cleaning");
}
}));
Этот хук отключит службу, которая не позволит вашему приложению отправлять новые задачи, и дождаться завершения всех существующих задач, прежде чем завершать работу JVM. Завершение ожидания будет заблокировано на 5 секунд и вернет true, если служба отключена. Это делается в цикле, чтобы вы были уверены, что служба в конечном итоге отключится. InterruptedException каждый раз проглатывается. Это лучший способ закрыть службу исполнителя, которая повторно используется во всем приложении.
Этот код не идеален. Если вы не уверены, что ваши задачи в конечном итоге будут завершены, вы можете подождать заданное время ожидания, а затем просто выйти, оставив работающие потоки. В этом случае имеет смысл также вызывать shutdownNow()
после тайм-аута в последней попытке прервать запущенные потоки (shutdownNow()
также выдаст вам список задач, ожидающих запуска). Если ваши задачи предназначены для реагирования на прерывание, это будет работать нормально.
Еще один интересный сценарий, когда у вас есть ScheduledExecutorService, который выполняет периодическую задачу. Единственный способ остановить цепочку периодических задач - вызвать shutdown()
.
РЕДАКТИРОВАТЬ: Я хотел бы добавить, что я бы не рекомендовал использовать хук отключения, как показано выше в общем случае: он может быть подвержен ошибкам и должен быть только в крайнем случае. Более того, если у вас зарегистрировано много перехватчиков завершения работы, порядок их запуска не определен, что может быть нежелательно. Я бы предпочел, чтобы приложение явно вызывало shutdown()
для InterruptedException
.
Ответ 2
Разве не вся идея для ExecutorService повторно использовать потоки? Так зачем так быстро уничтожать ExecutorService?
Да. Вы не должны часто разрушать и заново создавать ExecutorService
. При необходимости инициализируйте ExecutorService
(в основном при запуске) и оставляйте его активным до тех пор, пока не закончите с ним.
Разве это не рациональный способ просто создать ExecutorService (или пару в зависимости от того, сколько вам нужно), затем во время выполнения приложения передайте им задачи, как только они появятся, а затем при выходе из приложения или на некоторых других важных этапах завершите работу. исполнители?
Да. Рационально отключать ExecutorService
на важных этапах, таких как выход из приложения и т.д.
Второй вопрос, немного меньше сделок с платформой Android. Если некоторые из вас скажут, что это не лучшая идея каждый раз выключать исполнителей, и вы программируете на Android, не могли бы вы рассказать мне, как вы справляетесь с этими выключениями (а точнее, когда вы их выполняете), когда мы имеем дело с различными событиями приложения? жизненный цикл.
Предположим, что ExecutorService
совместно используется различными операциями в вашем приложении. Каждое действие будет приостановлено/возобновлено через различные промежутки времени, и все же вам потребуется один ExecutorService
для вашего приложения.
Вместо того чтобы управлять состоянием ExecutorService
в методах жизненного цикла Activity, переместите управление ExecutorService (создание/завершение) в свою пользовательскую службу.
Создайте ExecutorService
в Service => onCreate()
и правильно onDestroy()
его в onDestroy()
Рекомендуемый способ выключения ExecutorService
:
Как правильно отключить Java ExecutorService
Ответ 3
Служба ExecutorService должна быть закрыта, когда больше не требуется освобождать системные ресурсы и разрешать корректное завершение работы приложения. Поскольку потоки в ExecutorService могут быть не демоническими потоками, они могут помешать нормальному завершению работы приложения. Другими словами, ваше приложение продолжает работать после завершения основного метода.
Справочник
Chaper: 14 Страница: 814
Ответ 4
Причина вызова shutdown() в ExecutorService
Сегодня я столкнулся с ситуацией, когда мне нужно подождать, пока машина не будет готова, прежде чем запускать серию задач на этой машине.
Я делаю вызов REST на этот компьютер, если я не получаю 503 (сервер недоступен), тогда машина готова обработать мои запросы. Итак, я жду, пока не получу 200 (Успех) для первого вызова REST.
Существует несколько способов его достижения, я использовал ExecutorService для создания потока и запланировал его запуск через каждые X секунд. Итак, мне нужно остановить этот поток при условии, проверьте это...
final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
Runnable task = () -> {
try {
int statusCode = restHelper.firstRESTCall();
if (statusCode == 200) {
executor.shutdown();
}
} catch (Exception e) {
e.printStackTrace();
}
};
int retryAfter = 60;
executor.scheduleAtFixedRate(task, 0, retryAfter, TimeUnit.SECONDS);
Второй вопрос, немного меньшие сделки с платформой Android.
Возможно, я смогу ответить, если вы предоставите немного больше контекста!
Также из моего опыта разработки Android вам редко нужны темы. Вы разрабатываете игру или приложение, которое нуждается в потоках для производительности? Если нет, в Android у вас есть другие способы решения таких проблем, как сценарий, описанный выше. Вы можете использовать TimerTask, AsyncTask или Handlers или Loaders на основе контекста. Это связано с тем, что если UIThread долго ждет, вы знаете, что происходит:/
Ответ 5
Это действительно, несмотря на запланированные мероприятия, например, для ScheduledExecutorService: новые случаи забронированного назначения не будут выполняться.
Мы должны ожидать, что у вас есть комфортное приложение, в котором администратор агента выполняет поручения.
Я не уловил смысл без усилий? Возможно, вам нужно, чтобы ваше приложение не имело возможности отправлять больше назначений агентской администрации, и в то же время вам нужно сидеть сложа руки, чтобы завершить текущие обязательства N.
За исключением случаев, когда вы абсолютно уверены, что ваши поручения будут в конце концов, вы должны сидеть сложа руки для данного перерыва, а после этого просто выйти, оставляя бегущие струны.
В случае, если ваша деятельность предназначена для реагирования на помехи, это будет работать нормально.
Еще одна интригующая ситуация - это момент, когда у вас есть ScheduledExecutorService, который выполняет действие.
Лучший способ остановить цепочку действий - вызвать shutdown()