Причина виклику shutdown () на ExecutorService


84

Я читав про це зовсім небагато в останні пару годин, і я просто не бачу ніяких підстав ( дійсна причина) для виклику shutdown()на ExecutorService, якщо ми не будемо мати Humongous додаток , який зберігає, десятки і десятки різних послуг ВИКОНАВЕЦЬ, які не використовуються для довгий час.

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

Добре повернемося до мого запитання. Чи є причина викликати вимкнення телефону ExecutorServiceдуже часто або навіть відразу після того, як ви виконали перед ним якісь завдання? Я хотів би залишити позаду справу, коли хтось це робить, і відразу після цього дзвонить, awaitTermination()оскільки це підтверджується. Як тільки ми це зробимо, нам доведеться відтворювати нове ExecutorServiceзаново, щоб робити те саме. Хіба не вся ідея в тому, ExecutorServiceщоб повторно використовувати нитки? То навіщо знищувати ExecutorServiceтак швидко?

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

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

Питання другої сторони, трохи менші угоди з платформою Android. ЯКЩО хтось із вас скаже, що не найкраща ідея щоразу вимикати виконавців, і ви програмуєте на android, не могли б ви сказати мені, як ви обробляєте ці вимкнення (конкретно - коли ви їх виконуєте), коли ми маємо справу з різними подіями життєвий цикл застосування.

Через коментар CommonsWare я зробив пост нейтральним. Мені справді не цікаво сперечатися про це до смерті, і, здається, це веде туди. Мені цікаво дізнатись про те, що я тут запитав у досвідчених розробників, якщо вони хочуть поділитися своїм досвідом. Дякую.


3
"Я багато разів бачу зразки кодів, у яких весь час відбувається виклик shutdown () відразу після подання або виконання завдань" - сміливо використовуйте гіперпосилання для підтвердження своїх претензій. Особисто я ніколи не бачив жодного "зразка кодів", який би робив те, що ви заявляєте. Можливо, ви щось неправильно тлумачите, і ми можемо вказати на це лише тоді, коли ми знаємо, які «зразкові коди» ви перевіряєте.
CommonsWare

4
Привіт, CommonsWare. Перш за все, я бачу ваш агресивний тон (або так здається) до мене, який, на мою думку, тут не підтверджений. Я не намагався зобразити людей негативно. Що стосується Вашої цитати, я в основному говорив про Thinking In Java IV, багатозадачність. Ви можете знайти багато прикладів цього на прикладах Брюса Еккеля. Вони в основному прості, але тим не менше враження, яке Брюс справив на мене, було дуже часто використовувати відключення. У будь-якому випадку ви зосередилися на чомусь, що не було основною частиною мого допису. Я вилучив ці частини, бо я справді не хочу сперечатися з цього приводу.
Лукас

1
hay @CommonsWare in Thinking in java book by Bruce Eckel..in concurrency / Executor page 804 Четверте видання, він завжди використовує метод shutdown () відразу після надсилання або виконання завдань у простих додатках, щоб проілюструвати, як Executor працює, як сказав Лукас
Помилка

2
Я знаю, що це стара публікація, але я думаю, що питання ОП все ще стоїть і є дійсним. Я також стикався з багатьма зразками кодів, де "відбувається виклик shutdown () відразу після виконання ()". tutorials.jenkov.com/java-util-concurrent/executorservice.html (перший підручник, який з’являється, коли ви
гуглите

Дякую, у мене було те саме запитання, яке було порушено з цими "зразками кодів". journaldev.com/2340/…
Грегорі,

Відповіді:


57

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", якщо послуга буде відключена. Це робиться у циклі, щоб ви були впевнені, що служба врешті-решт вимкнеться. InterruptedException кожного разу проковтується. Це найкращий спосіб зупинити службу виконавця, яка повторно використовується у всьому додатку.

Цей код не ідеальний. Якщо ви абсолютно не впевнені, що ваші завдання врешті-решт припиняться, можливо, ви захочете дочекатися заданого часу очікування, а потім просто вийти, відмовившись від запущених потоків. У цьому випадку має сенс також зателефонувати shutdownNow()після закінчення тайм-ауту в останній спробі перервати запущені потоки ( shutdownNow()також надасть вам список завдань, які очікують на виконання). Якщо ваші завдання покликані реагувати на переривання, це буде працювати нормально.

Інший цікавий сценарій - це коли у вас є ScheduledExecutorService, який виконує періодичне завдання. Єдиний спосіб зупинити ланцюжок періодичних завдань - дзвінок shutdown().

РЕДАГУВАТИ: Я хотів би додати, що я б не рекомендував використовувати гачок відключення, як показано вище, у загальному випадку: він може бути схильним до помилок і повинен бути в крайньому випадку. Більше того, якщо у вас зареєстровано багато гачків вимкнення, порядок їх запуску невизначений, що може бути небажаним. Я волів би мати додаток явно викликати shutdown()на InterruptedException.


Вибачте Джованні за пізню відповідь, і дякую за це до речі. Так, я знаю про те, як працює Виконавець, що я намагався пояснити у своєму питанні. Вимкнення виконує те, що ви сказали, а також дозволяє збиральнику сміття збирати ці мертві потоки і фактично збирати екземпляр ExecutorService. Моє запитання було конкретним. Чи є підстави постійно викликати "shutdown ()", одразу після того, як ви подаєте / виконуєте щось на ExecutorService. Друга частина питання стосується суто архітектури Android. Якщо відповідь на попередню відповідь - ні, тоді коли викликати вимкнення під час та. життєвий цикл.
Лукас

3
Немає причин постійно телефонувати до shutdown (). Насправді це може бути абсолютно неправильно, оскільки це завадить вам повторно використовувати службу виконавця знову. Причиною викликати це в кінці життєвого циклу служби є те, що нитки можуть остаточно збирати сміття, як ви помітили. Якщо ви цього не зробите, ці потоки збережуть JVM живим, навіть якщо вони не працюють.
Джованні Ботта,

"Немає жодної причини постійно викликати shutdown (). Насправді це може бути абсолютно неправильним рішенням, оскільки це завадить вам повторно використовувати службу виконавця знову". Це саме моє міркування та моя дилема з початкового питання. Отже, повторюємось, запитання: Коли слід вимкнути службу ExecutiveService в життєвому циклі Android?
Лукас

2
У мене немає досвіду роботи з Android, але я гадаю, вам слід вимкнути його, коли ваша програма вимкнеться, щоб дозволити JVM остаточно вийти.
Джованні Ботта,

3
Розумію. Я пропоную вам використовувати кешований пул потоків і ніколи не shutdown()використовувати його, щоб не витрачати ресурси, коли це непотрібно. Якщо програма все-таки вимкнеться, потоки в пулі врешті-решт будуть збирати сміття (після того, як вони за замовчуванням простоюють 60 секунд) Зверніть увагу, що якщо ви хочете, щоб пул був обмеженим або хочете інший час життя потоку, ви можете створити ThreadPoolExecutorбезпосередньо.
Джованні Ботта

13

Хіба не вся ідея для ExecutorService повторно використовувати потоки? То чому так швидко знищувати ExecutorService?

Так. Не слід ExecutorServiceчасто руйнувати та відтворювати . Ініціалізуйте, ExecutorServiceколи вам потрібно (переважно під час запуску), і залишайте його активним, поки не закінчите з цим.

Хіба це не раціональний спосіб просто створити ExecutorService (або пару залежно від того, скільки вам потрібно), тоді під час запуску програми передайте їм завдання, як тільки вони з’являться, а потім при виході з програми або на деяких інших важливих етапах вимкнення цих виконавці?

Так. Раціонально зупиняти роботу ExecutorServiceна таких важливих етапах, як вихід програми тощо.

Питання другої сторони, трохи менші угоди з платформою Android. ЯКЩО хтось із вас скаже, що не найкраща ідея щоразу вимикати виконавців, і ви програмуєте на android, не могли б ви сказати мені, як ви обробляєте ці вимкнення (конкретно, коли ви їх виконуєте), коли ми маємо справу з різними подіями програми життєвий цикл.

Припустимо, що ExecutorServiceспільний доступ до різних видів діяльності у вашій програмі. Кожна діяльність буде призупинена / відновлена ​​через різні проміжки часу, і все одно вам потрібна одна ExecutorServiceдля вашої програми.

Замість того, щоб керувати станом ExecutorServiceу методах життєвого циклу Діяльності, перемістіть ExecutorService management (Creation / Shutdown) до Вашої користувацької Служби .

Створіть ExecutorServiceу службі => onCreate()та вимкніть її належним чином уonDestroy()

Рекомендований спосіб вимкнення ExecutorService:

Як правильно вимкнути java ExecutorService


3

Службу ExecutorService слід закрити, коли вона більше не потрібна для звільнення системних ресурсів та дозволу витонченого вимкнення програми. Оскільки потоки в ExecutorService можуть бути недемоновими, вони можуть перешкоджати нормальному завершенню роботи програми. Іншими словами, ваша програма продовжує працювати після завершення основного методу.

Довідник

Chaper: 14 Сторінка: 814


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


0

Це справді незважаючи на заплановані зобов'язання, наприклад, для ScheduledExecutorService: нові випадки зарезервованого призначення не працюватимуть.

Ми повинні очікувати, що у вас є програма для комфорту, в якій є адміністратор агента, який виконує N доручень.

Я не розумію, що це означає без зусиль? Можливо, вам потрібна ваша заявка, щоб не мати можливості подати більше доручень адміністрації агента, а тим часом вам потрібно сидіти, щоб завершити ваші поточні N-зобов’язання.

За винятком випадків, коли ви повністю впевнені, що ваші завдання досягнуть результату, вам слід посидіти на певний перерву, а після цього просто вийти, покинувши поточні струни.

У тому випадку, якщо ваші дії мають на меті реагувати на перешкоди, це спрацює нормально.

Інша інтригуюча ситуація - це момент, коли у вас є ScheduledExecutorService, який виконує певну діяльність.

Найкращий спосіб зупинити ланцюжок діяльності - це вимкнення виклику ()

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.