Хто викликає метод Java Thread interrupt (), якщо я цього не зробив?


87

Я читав і перечитував Java-паралелізм на практиці, прочитав тут кілька тем з цього питання, прочитав статтю IBM, що стосується InterruptedException, і все-таки є щось, чого я просто не розумію, і, на мою думку, може бути порушено два питання:

  1. Якщо я ніколи не перериваю інші потоки сам, що може викликати InterruptedException ?

  2. Якщо я ніколи не перериваю інші потоки сам, використовуючи interrupt () (скажімо, тому, що я використовую інші засоби для скасування своїх робочих потоків, як отруйні таблетки та цикл стилю while (! чи означає тоді InterruptedException ? Що я повинен робити, ловлячи одного? Вимкнути мій додаток?

Відповіді:


50

Механізм переривання потоку - найкращий спосіб отримати (співпрацюючий) потік, щоб відповісти на запит, щоб зупинити те, що він робить. Будь-який потік (включаючи сам потік, на мою думку) міг би викликати interrupt()Thread.

На практиці звичайні випадки використання interrupt()включають певний фреймворк або менеджера, який каже деякий робочий потік зупинити те, що вони роблять. Якщо робочий потік "поінформований про переривання", він помітить, що він був перерваний через виняток або періодично перевіряючи його перерваний прапор. Помітивши, що його було перервано, добре вихований потік відмовиться від того, що робить, і закінчить сам.

Припускаючи наведений вище варіант використання, ваш код, ймовірно, буде перерваний, якщо він запускається в рамках Java або з якогось робочого потоку. І коли він переривається, ваш код повинен відмовитися від того, що він робить, і змусити себе закінчити найбільш підходящими засобами. Залежно від того, як був викликаний ваш код, це може бути зроблено шляхом повернення або викидання відповідного винятку. Але це, мабуть, не повинно дзвонити System.exit(). (Ваша програма не обов'язково знає, чому її було перервано, і вона точно не знає, чи є інші потоки, які потрібно перервати фреймворком.)

З іншого боку, якщо ваш код не призначений для роботи під контролем якоїсь основи, ви можете стверджувати, що InterruptedExceptionце є несподіваним винятком; тобто помилка. У цьому випадку ви повинні поводитися з винятком, як з іншими помилками; наприклад, оберніть його у неперевіреному винятку, і ловіть та реєструйте його в той самий момент, коли ви маєте справу з іншими несподіваними неперевіреними винятками. (Або ж ваша програма може просто ігнорувати переривання і продовжувати робити те, що робила.)


1) Якщо я ніколи не перериваю інші потоки сам, що може викликати InterruptedException?

Одним із прикладів є те, якщо ваші Runnableоб’єкти виконуються за допомогою служби ExecutorServiceі shutdownNow()викликається в службі. І теоретично, будь-який сторонній пул потоків або система управління потоками може законно зробити щось подібне.

2) Якщо я ніколи не перериваю інші потоки сам, використовуючи interrupt () ... що означає InterruptedExceptionтоді? Що я повинен робити, ловлячи одного? Вимкнути мій додаток?

Вам потрібно проаналізувати кодову базу, щоб з’ясувати, що interrupt()і чому робить дзвінки. Як тільки ви це зрозуміли, ви зможете зрозуміти, що >> ваша << частина програми повинна робити.

Поки ви не знаєте, чому InterruptedExceptionкидають, я б порадив розглядати це як серйозну помилку; наприклад, надрукуйте стек у файл журналу та вимкніть програму. (Очевидно, це не завжди правильна відповідь ... але справа в тому, що це "помилка", і на неї потрібно звернути увагу розробника / супровідника.)

3) Як дізнатися, хто / що телефонує interrupt()?

На це немає хорошої відповіді. Найкраще, що я можу запропонувати, - це встановити точку зупинки на Thread.interrupt()і переглянути стек дзвінків.


12

Якщо ви вирішите інтегрувати свій код з іншими бібліотеками, вони можуть звернутися interrupt()до вашого коду. наприклад, якщо ви вирішите в майбутньому виконати свій код у службі ExecutorService , то це може призвести до вимкнення через interrupt().

Кажучи коротко, я хотів би розглянути не тільки там , де ваш код працює в даний час , але і в якому контексті він може працювати в майбутньому. наприклад, ви збираєтесь покласти його в бібліотеку? Контейнер? Як інші люди використовуватимуть це? Ви збираєтеся використовувати його повторно?


Я думав, що тільки shutdownNow викликає метод interrupt (). Це справедливо і для вимкнення?
Harinder

9

Як зазначали інші, переривання потоку (насправді, переривання виклику блокування) зазвичай використовується для чистого виходу або скасування поточної діяльності.

Однак не слід розглядати InterruptedExceptionпоодинці як "команду кинути". Натомість вам слід думати про переривання як про засіб контролю поточного стану потоків, приблизно так само, як Object.notify()це робить. Таким же чином, як ви перевіряли поточний стан після пробудження від дзвінка Object.wait()(ви не припускаєте, що пробудження означає, що ваш стан очікування виконано), після підштовхування з перериванням слід перевірити, чому вас перервали . Як правило, це можна зробити. Наприклад, java.util.concurrent.FutureTaskмає isCancelled()метод.

Зразок коду:

public void run() {
    ....
    try {
        .... // Calls that may block.
    } catch (InterruptedException e) {
        if (!running) {  // Add preferred synchronization here.
            return; // Explicit flag says we should stop running.
        }
        // We were interrupted, but the flag says we're still running.
        // It would be wrong to always exit here. The interrupt 'nudge'
        // could mean something completely different. For example, it
        // could be that the thread was blocking on a read from a particular
        // file, and now we should read from a different file.
        // Interrupt != quit (not necessarily).
    }
    ....
}
public void stop() {
    running = false; // Add preferred synchronization here.
    myThread.interrupt();
}

3

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

Можливі несподівані переривання, що надходять із JRE, скасовують завдання java.util.concurrentта вимикають аплети.

Обробка переривань ниток зазвичай пишеться неправильно. Тому я пропоную архітектурне рішення уникати переривань, де це можливо. Однак переривання обробки коду завжди слід писати правильно. Не вдається зняти переривання з платформи.


Привіт Томе, я пам'ятаю твоє ім'я з cljp;) Ну, саме так: мені ніколи не доводилося кидати interrupt () самому ... Якщо я не вловлю InterruptException і не потрібно повторно стверджувати статус перерваного, але це все ще не 100% мені зрозуміло. Я тут новачок і здивований кількістю схвалень та відповідей / коментарів (як правильних, так і неправильних): очевидно, що це тема, яка не є тривіальною або, принаймні, як правило, недостатньо добре поясненою. Тим не менше, завдяки всім публікаціям, я починаю отримувати більш чітке уявлення про те, що відбувається :)
SyntaxT3rr0r

3

Ви можете навчитися цьому, створивши власний клас потоку (розширення java.lang.Thread) та перевизначення interrupt()методу, в якому ви записуєте стек, скажімо, у поле String, а потім переносите в super.interrupt ().

public class MyThread extends Thread {

    public volatile String interruptStacktrace; // Temporary field for debugging purpose.

    @Override
    public void interrupt() {
        interruptStacktrace = dumpStack(); // You implement it somehow...

        super.interrupt();
    }
}

1

Як уже зазначалося, інша бібліотека може перервати ваші потоки. Навіть якщо бібліотека не має явного доступу до потоків з вашого коду, вони все одно можуть отримати список запущених потоків і перервати їх таким чином за допомогою наступного методу .


1

Думаю, я розумію, чому вас трохи бентежить перерва. Будь ласка, розгляньте мої відповіді в рядку:

Якщо я ніколи не перериваю інші потоки сам, що може викликати InterruptedException ?

По-перше, ви можете перервати інші потоки; Я знаю, що в JCiP згадується, що ви ніколи не повинні переривати потоки, якими ви не володієте; однак це твердження повинно бути належним чином зрозуміле. Це означає, що ваш код, який може працювати в будь-якому довільному потоці, не повинен обробляти переривання, оскільки, оскільки він не є власником потоку, він не має уявлення про свою політику переривання. Отже, ви можете вимагати переривання в інших потоках, але дозвольте його власникові вжити дії щодо переривання; у ньому закладена політика переривань, а не ваш код завдання; принаймні, будьте ввічливі, щоб встановити прапор переривання!

Є багато способів, чому все-таки можуть бути перебої, можуть бути тайм-аути, переривання JVM тощо.

Якщо я ніколи ніколи не перериваю інші потоки сам, використовуючи interrupt () (скажімо, тому що я використовую інші засоби для скасування своїх робочих потоків, як отруйні таблетки та цикл стилю while (! чи означає тоді InterruptedException? Що я повинен робити, ловлячи одного? Вимкнути мій додаток?

Тут потрібно бути дуже обережним; якщо ви є власником потоку, який викинув InterruptedException (IE), тоді ви знаєте, що робити, перехопивши його, скажімо, ви можете вимкнути свою програму / послугу або замінити цю вбиту нитку новою! Однак, якщо ви не є власником потоку, то після лову IE або перекиньте його вище в стек викликів, або після того, як щось зробите (можливо, ведете журнал), скиньте стан перерваного, щоб код, який є власником цього потоку, коли керування досягло його, міг дізнайтеся, що нитка була перервана, і, отже, вживайте дій, як це буде, оскільки лише вона знає політику переривання.

Сподіваюся, це допомогло.


0

InterruptedExceptionКаже про те , що процедура може бути перервана, але не обов'язково , що це буде.

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

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