2013-04-20 2 views
45

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

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

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

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

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

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

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

+1

«Я вижу много раз образцы кодов, в которых все время происходит вызов shutdown() сразу после отправки или выполнения задач» - не стесняйтесь используйте гиперссылки, чтобы предоставить доказательства ваших требований. Лично я никогда не видел никаких «примеров кодов», которые делают то, что вы заявляете. Возможно, вы что-то неправильно истолковываете, и мы можем только указать это вам, если мы знаем, какие «образцы кода» вы изучаете. – CommonsWare

+2

Привет CommonsWare. Прежде всего, я вижу агрессивный тон вашего (или так кажется) ко мне, который, я думаю, не подтвержден здесь. Я не пытался изображать людей отрицательным образом. Что касается вашей цитаты, я в основном говорил о выпуске «Мышление в Java IV», «Многозадачность». Вы можете найти много примеров этого в примерах Брюса Эккела. Они в основном простые, но, тем не менее, впечатление, которое наложил на меня Брюс, было очень часто отключать работу. В любом случае, вы сосредоточились на чем-то, что не было основной частью моего поста. Я удалил эти части, потому что я действительно не хочу спорить об этом. – Lucas

+1

hay @CommonsWare in Thinking in java book by Bruce Eckel..in concurrency/Executor page 804 Четвертое издание, он всегда использует метод shutdown() сразу после отправки или выполнения задач в простых приложениях, чтобы проиллюстрировать, как Исполнитель работает, как сказал Лукас. – Error

ответ

28

Метод shutdown() делает одно: запрещает клиентам отправлять больше работы службе исполнителя. Это означает, что все существующие задачи все равно будут завершены до тех пор, пока не будут предприняты другие действия. Это справедливо даже для запланированных задач, например для 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, если служба отключена. Это делается в цикле, так что вы уверены, что служба в конечном итоге отключится. Прерывание исключается каждый раз. Это лучший способ отключить службу-исполнитель, которая повторно используется во всем приложении.

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

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

EDIT: Я хотел бы добавить, что я бы не рекомендовал использовать крюк остановки, как показано выше, в общем случае: он может быть подвержен ошибкам и должен быть только последним. Более того, если у вас зарегистрировано много остановленных крючков, порядок, в котором они будут выполняться, не определен, что может быть нежелательным. Я предпочел бы, чтобы приложение явно вызывало shutdown() по адресу InterruptedException.

+0

Извините Джованни за поздний ответ и благодарю вас за это. Да, я знаю, как работает Исполнитель, который я пытался объяснить в моем вопросе.Выключение делает то, что вы сказали, а также позволяет сборщику мусора собирать эти мертвые потоки и фактически собирать экземпляр ExecutorService. Мой вопрос был конкретным. Есть ли причина называть «shutdown()» все время сразу после отправки/выполнения чего-либо в ExecutorService. Вторая часть вопроса строго связана с архитектурой Android. Если ответ на предыдущий - нет, тогда, когда вызывать выключение во время и. жизненный цикл. – Lucas

+2

Нет причин постоянно вызывать shutdown(). Фактически, это может быть абсолютно неправильным, потому что это не позволит вам повторно использовать службу исполнителя снова. Причиной назвать его в конце жизненного цикла службы является то, что потоки могут быть окончательно собраны мусором, как вы заметили. Если вы этого не сделаете, эти потоки сохранят JVM в живых, даже если они простаивают. –

+0

«Нет причин постоянно вызывать shutdown(). На самом деле это может быть абсолютно неправильным, потому что это не позволит вам снова использовать службу исполнителя». Это точно мои рассуждения, и моя диллема из первоначального вопроса. Поэтому, чтобы повторить, возникает вопрос: когда я должен отключить свой ExecutiveService в жизненном цикле Android? – Lucas

3

Не все идеи для ExecutorService для повторного использования потоков? Так зачем так быстро разрушить Исполнительную службу?

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

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

Да. Разумно отключить ExecutorService на важных этапах, таких как выход приложения и т. Д.

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

Предположим, что ExecutorService делится на различные мероприятия в вашей заявке. Каждое действие будет приостановлено/возобновлено с разным промежутком времени, и вам все равно потребуется ExecutorService за ваше приложение.

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

Создание ExecutorService в сервис =>onCreate() и выключение его правильно в onDestroy()

Рекомендуемый способ отключения ExecutorService:

How to properly shutdown java ExecutorService

0

Причина вызова 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 у вас есть другие способы решения таких проблем, как сценарий, описанный выше. Вы можете использовать TimerTask, AsyncTask или Handlers или Loaders на основе контекста. Это связано с тем, что, если UIThread ждет вас долго, вы знаете, что происходит:/

Смежные вопросы