Подтвердить что ты не робот

Причина вызова shutdown() для ExecutorService

Я читал об этом довольно много за последние пару часов, и я просто не вижу никакой причины (действительной причины) для вызова shutdown() на ExecutorService, если у нас нет огромного приложения, которое хранит, десятки и десятки различных служб executor, которые не используются в течение длительного времени.

Единственное (из того, что я понял), что происходит при завершении работы, - это делать то, что делает нормальный поток, как только он это сделает. Когда обычный поток завершит выполнение метода Runnable (или Callable), он будет передан в сборщик мусора для сбора. С помощью Executor Service потоки будут просто приостановлены, они не будут отмечены для сборки мусора. Для этого необходимо отключение.

Хорошо, вернемся к моему вопросу. Есть ли какая-либо причина вызывать завершение работы на ExecutorService очень часто или даже сразу после предоставления ему каких-либо задач? Я хотел бы оставить позади случай, когда кто-то делает это, и сразу после этого вызывает awaitTermination() поскольку это проверено. Как только мы это сделаем, мы должны заново создать новый ExecutorService, чтобы сделать то же самое. Разве не вся идея для ExecutorService повторно использовать потоки? Так зачем так быстро уничтожать ExecutorService?

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

Я хотел бы получить ответ от некоторых опытных программистов, которые пишут много асинхронного кода с использованием ExecutorServices.

Второй вопрос, немного меньше сделок с платформой Android. Если некоторые из вас скажут, что не стоит каждый раз закрывать исполнителей, и вы программируете на Android, не могли бы вы рассказать, как вы справляетесь с этими выключениями (а точнее - когда вы их выполняете), когда мы имеем дело с различными событиями жизненный цикл приложения.

Из-за комментария CommonsWare я сделал пост нейтральным. Я действительно не заинтересован в том, чтобы спорить об этом до смерти, и, кажется, это ведет там. Меня интересует только то, что я спросил у опытных разработчиков, если они хотят поделиться своим опытом. Благодарю.

4b9b3361

Ответ 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()