Кто вызывает метод прерывания потока Java (), если я нет?


87

Я прочитал и перечитал Java Concurrency in Practice, я прочитал здесь несколько тем по этой теме, я прочитал статью IBM Работа с InterruptedException, но есть кое-что, что я просто не понимаю, что, по моему мнению, может быть нарушено на два вопроса:

  1. Если я никогда сам никогда не прерываю другие потоки, что может вызвать InterruptedException ?

  2. Если я никогда не прерываю другие потоки сам, используя interrupt () (скажем, потому что я использую другие средства для отмены моих рабочих потоков, например, отравленные таблетки и цикл в стиле while (! Отменен) [как оба объяснены в JCIP]), то что делает InterruptedException то значит? Что мне делать, если я поймаю одного? Закрыть мое приложение?

Ответы:


50

Механизм прерывания потока - предпочтительный способ заставить (взаимодействующий) поток ответить на запрос, чтобы остановить то, что он делает. Любой поток (включая сам поток, я думаю) может вызывать поток interrupt().

На практике нормальные варианты использования 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;) Ну, точно: мне никогда не приходилось самому бросать прерывание () ... Если только я не поймаю InterruptedException и мне нужно повторно подтвердить статус прерывания, но это все еще не 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 (! Отменен) [как оба объяснены в JCIP]), то что тогда означает InterruptedException? Что мне делать, если я поймаю одного? Закрыть мое приложение?

Здесь нужно быть очень осторожным; если вы владеете потоком, который выбросил InterruptedException (IE), тогда вы знаете, что делать после его обнаружения, скажем, вы можете закрыть свое приложение / службу или вы можете заменить этот убитый поток новым! Однако, если вы не владеете потоком, то, поймав IE, либо перебросьте его выше по стеку вызовов, либо после чего-то (может вести журнал) сбросьте состояние прерывания, чтобы код, владеющий этим потоком, когда управление достигнет его, мог узнайте, что поток был прерван, и, следовательно, примите меры, поскольку только он знает политику прерывания.

Надеюсь, это помогло.


0

В них InterruptedExceptionговорится, что распорядок может быть прерван, но не обязательно, что это произойдет.

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.